From 20ed4fbbd46f359ca1436b2d3b9d17527c01df54 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 15 Nov 2018 08:19:58 -0800 Subject: First pass on widget version of heap --- packages/instant/src/constants.ts | 1 + packages/instant/src/util/heap.ts | 87 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 packages/instant/src/util/heap.ts diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 5bd2349b3..994be9788 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -16,6 +16,7 @@ export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; +export const HEAP_ANALYTICS_DEVELOPMENT_APP_ID = '507265531'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts new file mode 100644 index 000000000..399ac3f6f --- /dev/null +++ b/packages/instant/src/util/heap.ts @@ -0,0 +1,87 @@ +import { ObjectMap } from '@0x/types'; +import { logUtils } from '@0x/utils'; + +import { HEAP_ANALYTICS_DEVELOPMENT_APP_ID } from '../constants'; + +export interface HeapAnalytics { + loaded: boolean; + identify(id: string, idType: string): void; + track(eventName: string, eventProperties?: ObjectMap): void; + resetIdentity(): void; + addUserProperties(properties: ObjectMap): void; + addEventProperties(properties: ObjectMap): void; + removeEventProperty(property: string): void; + clearEventProperties(): void; +} +interface ModifiedWindow { + heap?: HeapAnalytics; + zeroExInstantLoadedHeap?: boolean; +} +const getWindow = (): ModifiedWindow => { + return window as ModifiedWindow; +}; +// Typescript-compatible version of https://docs.heapanalytics.com/docs/installation +const setupZeroExInstantHeap = () => { + /* tslint:disable */ + ((window as any).heap = (window as any).heap || []), + ((window as any).heap.load = function(e: any, t: any) { + ((window as any).heap.appid = e), ((window as any).heap.config = t = t || {}); + var r = t.forceSSL || 'https:' === (document.location as Location).protocol, + a = document.createElement('script'); + (a.type = 'text/javascript'), + (a.async = !0), + (a.src = (r ? 'https:' : 'http:') + '//cdn.heapanalytics.com/js/heap-' + e + '.js'); + var n = document.getElementsByTagName('script')[0]; + (n.parentNode as Node).insertBefore(a, n); + for ( + var o = function(e: any) { + return function() { + (window as any).heap.push([e].concat(Array.prototype.slice.call(arguments, 0))); + }; + }, + p = [ + 'addEventProperties', + 'addUserProperties', + 'clearEventProperties', + 'identify', + 'resetIdentity', + 'removeEventProperty', + 'setEventProperties', + 'track', + 'unsetEventProperty', + ], + c = 0; + c < p.length; + c++ + ) + (window as any).heap[p[c]] = o(p[c]); + }); + // TODO: use production heap id once environment utils merged + (window as any).heap.load(HEAP_ANALYTICS_DEVELOPMENT_APP_ID); + /* tslint:enable */ + + const curWindow = getWindow(); + // Set property to specify that this is zeroEx's heap + curWindow.zeroExInstantLoadedHeap = true; + return curWindow.heap as HeapAnalytics; +}; + +export const heapUtil = { + getHeap: (): HeapAnalytics | null => { + const curWindow = getWindow(); + const hasOtherExistingHeapIntegration = curWindow.heap && !curWindow.zeroExInstantLoadedHeap; + if (hasOtherExistingHeapIntegration) { + logUtils.log('Heap integration already exists'); + return null; + } + + const zeroExInstantHeapIntegration = curWindow.zeroExInstantLoadedHeap && curWindow.heap; + if (zeroExInstantHeapIntegration) { + logUtils.log('Using existing 0x instant heap'); + return zeroExInstantHeapIntegration; + } + + logUtils.log('Setting up heap'); + return setupZeroExInstantHeap(); + }, +}; -- cgit v1.2.3 From 61f227e123218ba76a7fdf7fc2ee89171c2bf16c Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 15 Nov 2018 10:43:42 -0800 Subject: feat(instant): Heap middleware and first tracking events --- .../src/components/zero_ex_instant_container.tsx | 5 +++ packages/instant/src/redux/analytics_middleware.ts | 38 ++++++++++++++++++++++ packages/instant/src/redux/store.ts | 7 ++-- packages/instant/src/util/analytics.ts | 35 ++++++++++++++++++++ packages/instant/src/util/heap.ts | 13 ++++---- 5 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 packages/instant/src/redux/analytics_middleware.ts create mode 100644 packages/instant/src/util/analytics.ts diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 698bfef17..d977b0690 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -10,6 +10,7 @@ import { SelectedAssetInstantHeading } from '../containers/selected_asset_instan import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; import { OrderProcessState, SlideAnimationState } from '../types'; +import { analytics } from '../util/analytics'; import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; @@ -68,6 +69,10 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon ); } + // tslint:disable-next-line:prefer-function-over-method + public componentDidMount(): void { + analytics.track('Widget - Opened'); + } private readonly _handleSymbolClick = (): void => { this.setState({ tokenSelectionPanelAnimationState: 'slidIn', diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts new file mode 100644 index 000000000..8dd674e94 --- /dev/null +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -0,0 +1,38 @@ +import { ObjectMap } from '@0x/types'; +import * as _ from 'lodash'; +import { Middleware } from 'redux'; + +import { analytics } from '../util/analytics'; + +import { AccountState } from './../types'; +import { Action, ActionTypes } from './actions'; +import { State } from './reducer'; + +export const analyticsMiddleware: Middleware = store => next => middlewareAction => { + const prevState = store.getState() as State; + const nextAction = next(middlewareAction) as Action; + const nextState = store.getState() as State; + + const curAccount = nextState.providerState.account; + const prevAccount = prevState.providerState.account; + switch (nextAction.type) { + case ActionTypes.SET_ACCOUNT_STATE_READY: + if (curAccount.state === AccountState.Ready && !_.isEqual(curAccount, prevAccount)) { + const ethAddress = curAccount.address; + analytics.addUserProperties({ ethAddress }); + analytics.track('Wallet - Ready'); + } + break; + case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: + if ( + curAccount.state === AccountState.Ready && + curAccount.ethBalanceInWei && + !_.isEqual(curAccount, prevAccount) + ) { + const ethBalanceInWei = curAccount.ethBalanceInWei.toString(); + analytics.addUserProperties({ ethBalanceInWei }); + } + } + + return nextAction; +}; diff --git a/packages/instant/src/redux/store.ts b/packages/instant/src/redux/store.ts index 20710765d..54dfe58c4 100644 --- a/packages/instant/src/redux/store.ts +++ b/packages/instant/src/redux/store.ts @@ -1,7 +1,8 @@ import * as _ from 'lodash'; -import { createStore, Store as ReduxStore } from 'redux'; -import { devToolsEnhancer } from 'redux-devtools-extension/developmentOnly'; +import { applyMiddleware, createStore, Store as ReduxStore } from 'redux'; +import { composeWithDevTools, devToolsEnhancer } from 'redux-devtools-extension/developmentOnly'; +import { analyticsMiddleware } from './analytics_middleware'; import { createReducer, State } from './reducer'; export type Store = ReduxStore; @@ -9,6 +10,6 @@ export type Store = ReduxStore; export const store = { create: (initialState: State): Store => { const reducer = createReducer(initialState); - return createStore(reducer, initialState, devToolsEnhancer({})); + return createStore(reducer, initialState, composeWithDevTools(applyMiddleware(analyticsMiddleware))); }, }; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts new file mode 100644 index 000000000..4de3e5eff --- /dev/null +++ b/packages/instant/src/util/analytics.ts @@ -0,0 +1,35 @@ +import { ObjectMap } from '@0x/types'; +import { logUtils } from '@0x/utils'; + +import { HeapAnalytics, heapUtil } from './heap'; + +export class Analytics { + public static init(): Analytics { + return new Analytics(); + } + public track(eventName: string, eventProperties?: ObjectMap): void { + console.log('HEAP: tracking', eventName, eventProperties); + this._evaluteHeapCall(heap => heap.track(eventName, eventProperties)); + } + public addUserProperties(properties: ObjectMap): void { + console.log('HEAP: adding user properties', properties); + this._evaluteHeapCall(heap => heap.addUserProperties(properties)); + } + public addEventProperties(properties: ObjectMap): void { + this._evaluteHeapCall(heap => heap.addEventProperties(properties)); + } + private _evaluteHeapCall(heapFunctionCall: (heap: HeapAnalytics) => void): void { + const curHeap = heapUtil.getHeap(); + if (curHeap) { + try { + heapFunctionCall(curHeap); + } catch (e) { + // We never want analytics to crash our React component + // TODO: error reporter here + logUtils.log('Analytics error', e); + } + } + } +} + +export const analytics = Analytics.init(); diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 399ac3f6f..2f2c221b1 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -20,8 +20,13 @@ interface ModifiedWindow { const getWindow = (): ModifiedWindow => { return window as ModifiedWindow; }; -// Typescript-compatible version of https://docs.heapanalytics.com/docs/installation + const setupZeroExInstantHeap = () => { + const curWindow = getWindow(); + // Set property to specify that this is zeroEx's heap + curWindow.zeroExInstantLoadedHeap = true; + + // Typescript-compatible version of https://docs.heapanalytics.com/docs/installation /* tslint:disable */ ((window as any).heap = (window as any).heap || []), ((window as any).heap.load = function(e: any, t: any) { @@ -60,9 +65,6 @@ const setupZeroExInstantHeap = () => { (window as any).heap.load(HEAP_ANALYTICS_DEVELOPMENT_APP_ID); /* tslint:enable */ - const curWindow = getWindow(); - // Set property to specify that this is zeroEx's heap - curWindow.zeroExInstantLoadedHeap = true; return curWindow.heap as HeapAnalytics; }; @@ -71,17 +73,14 @@ export const heapUtil = { const curWindow = getWindow(); const hasOtherExistingHeapIntegration = curWindow.heap && !curWindow.zeroExInstantLoadedHeap; if (hasOtherExistingHeapIntegration) { - logUtils.log('Heap integration already exists'); return null; } const zeroExInstantHeapIntegration = curWindow.zeroExInstantLoadedHeap && curWindow.heap; if (zeroExInstantHeapIntegration) { - logUtils.log('Using existing 0x instant heap'); return zeroExInstantHeapIntegration; } - logUtils.log('Setting up heap'); return setupZeroExInstantHeap(); }, }; -- cgit v1.2.3 From 2e61050a223a52b4b984034463887b0d579ce9b8 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 15 Nov 2018 10:48:20 -0800 Subject: Use pure functions instead of class --- packages/instant/src/util/analytics.ts | 51 ++++++++++++++++------------------ 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 4de3e5eff..3e2a996cf 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -3,33 +3,30 @@ import { logUtils } from '@0x/utils'; import { HeapAnalytics, heapUtil } from './heap'; -export class Analytics { - public static init(): Analytics { - return new Analytics(); - } - public track(eventName: string, eventProperties?: ObjectMap): void { - console.log('HEAP: tracking', eventName, eventProperties); - this._evaluteHeapCall(heap => heap.track(eventName, eventProperties)); - } - public addUserProperties(properties: ObjectMap): void { - console.log('HEAP: adding user properties', properties); - this._evaluteHeapCall(heap => heap.addUserProperties(properties)); - } - public addEventProperties(properties: ObjectMap): void { - this._evaluteHeapCall(heap => heap.addEventProperties(properties)); - } - private _evaluteHeapCall(heapFunctionCall: (heap: HeapAnalytics) => void): void { - const curHeap = heapUtil.getHeap(); - if (curHeap) { - try { - heapFunctionCall(curHeap); - } catch (e) { - // We never want analytics to crash our React component - // TODO: error reporter here - logUtils.log('Analytics error', e); - } +const evaluteHeapCall = (heapFunctionCall: (heap: HeapAnalytics) => void): void => { + const curHeap = heapUtil.getHeap(); + if (curHeap) { + try { + heapFunctionCall(curHeap); + } catch (e) { + // We never want analytics to crash our React component + // TODO: error reporter here + logUtils.log('Analytics error', e); } } -} +}; -export const analytics = Analytics.init(); +export const analytics = { + addUserProperties: (properties: ObjectMap): void => { + console.log('HEAP: adding user properties', properties); + evaluteHeapCall(heap => heap.addUserProperties(properties)); + }, + addEventProperties: (properties: ObjectMap): void => { + console.log('HEAP: adding user properties', properties); + evaluteHeapCall(heap => heap.addEventProperties(properties)); + }, + track: (eventName: string, eventProperties?: ObjectMap): void => { + console.log('HEAP: tracking', eventName, eventProperties); + evaluteHeapCall(heap => heap.track(eventName, eventProperties)); + }, +}; -- cgit v1.2.3 From 0a38bf8fd6d2b98a84671a152cc380458d2e5e7e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 15 Nov 2018 11:24:48 -0800 Subject: Report ETH in units --- packages/instant/src/redux/analytics_middleware.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 8dd674e94..01be9b988 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -1,11 +1,14 @@ import { ObjectMap } from '@0x/types'; +import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import { Middleware } from 'redux'; +import { ETH_DECIMALS } from '../constants'; +import { AccountState } from '../types'; import { analytics } from '../util/analytics'; -import { AccountState } from './../types'; import { Action, ActionTypes } from './actions'; + import { State } from './reducer'; export const analyticsMiddleware: Middleware = store => next => middlewareAction => { @@ -29,8 +32,11 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction curAccount.ethBalanceInWei && !_.isEqual(curAccount, prevAccount) ) { - const ethBalanceInWei = curAccount.ethBalanceInWei.toString(); - analytics.addUserProperties({ ethBalanceInWei }); + const ethBalanceInUnitAmount = Web3Wrapper.toUnitAmount( + curAccount.ethBalanceInWei, + ETH_DECIMALS, + ).toString(); + analytics.addUserProperties({ ethBalanceInUnitAmount }); } } -- cgit v1.2.3 From 450814ad80bb22332579e8ba54b58e1c06f34f71 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 15 Nov 2018 11:28:44 -0800 Subject: Introduce ANALYTICS_ENABLED constant --- packages/instant/src/constants.ts | 1 + packages/instant/src/util/analytics.ts | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 994be9788..f46b0ca21 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -16,6 +16,7 @@ export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; +export const ANALYTICS_ENABLED = true; // TODO: change when we can switch on dev export const HEAP_ANALYTICS_DEVELOPMENT_APP_ID = '507265531'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 3e2a996cf..6b6115abe 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,9 +1,15 @@ import { ObjectMap } from '@0x/types'; import { logUtils } from '@0x/utils'; +import { ANALYTICS_ENABLED } from '../constants'; + import { HeapAnalytics, heapUtil } from './heap'; const evaluteHeapCall = (heapFunctionCall: (heap: HeapAnalytics) => void): void => { + if (!ANALYTICS_ENABLED) { + return; + } + const curHeap = heapUtil.getHeap(); if (curHeap) { try { -- cgit v1.2.3 From ca9bb45327d2c5a8a83f2d261b134bf8489b3395 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 15 Nov 2018 11:29:11 -0800 Subject: Move where we track widget opened, and report on networkId and providerName --- packages/instant/src/components/zero_ex_instant_container.tsx | 4 ---- packages/instant/src/components/zero_ex_instant_provider.tsx | 10 ++++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index d977b0690..8c3bdc6b6 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -69,10 +69,6 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon ); } - // tslint:disable-next-line:prefer-function-over-method - public componentDidMount(): void { - analytics.track('Widget - Opened'); - } private readonly _handleSymbolClick = (): void => { this.setState({ tokenSelectionPanelAnimationState: 'slidIn', diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 18e71edb6..c187f98ee 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -13,6 +13,7 @@ import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; import { assetUtils } from '../util/asset'; +import { analytics } from '../util/analytics'; import { errorFlasher } from '../util/error_flasher'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { Heartbeater } from '../util/heartbeater'; @@ -120,6 +121,15 @@ export class ZeroExInstantProvider extends React.Component Date: Thu, 15 Nov 2018 11:33:04 -0800 Subject: Take out console.logs --- packages/instant/src/util/analytics.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 6b6115abe..dd595529d 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -24,15 +24,12 @@ const evaluteHeapCall = (heapFunctionCall: (heap: HeapAnalytics) => void): void export const analytics = { addUserProperties: (properties: ObjectMap): void => { - console.log('HEAP: adding user properties', properties); evaluteHeapCall(heap => heap.addUserProperties(properties)); }, addEventProperties: (properties: ObjectMap): void => { - console.log('HEAP: adding user properties', properties); evaluteHeapCall(heap => heap.addEventProperties(properties)); }, track: (eventName: string, eventProperties?: ObjectMap): void => { - console.log('HEAP: tracking', eventName, eventProperties); evaluteHeapCall(heap => heap.track(eventName, eventProperties)); }, }; -- cgit v1.2.3 From 71aeb7cddcd2a1faf7a4dc46d828ad8471019f37 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 15 Nov 2018 11:35:47 -0800 Subject: Linting --- packages/instant/src/components/zero_ex_instant_container.tsx | 1 - packages/instant/src/components/zero_ex_instant_provider.tsx | 2 +- packages/instant/src/redux/analytics_middleware.ts | 1 - packages/instant/src/redux/store.ts | 2 +- packages/instant/src/util/heap.ts | 1 - 5 files changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 8c3bdc6b6..698bfef17 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -10,7 +10,6 @@ import { SelectedAssetInstantHeading } from '../containers/selected_asset_instan import { ColorOption } from '../style/theme'; import { zIndex } from '../style/z_index'; import { OrderProcessState, SlideAnimationState } from '../types'; -import { analytics } from '../util/analytics'; import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index c187f98ee..cfc542a59 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -12,8 +12,8 @@ import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; -import { assetUtils } from '../util/asset'; import { analytics } from '../util/analytics'; +import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { Heartbeater } from '../util/heartbeater'; diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 01be9b988..2b3ebf529 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -1,4 +1,3 @@ -import { ObjectMap } from '@0x/types'; import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import { Middleware } from 'redux'; diff --git a/packages/instant/src/redux/store.ts b/packages/instant/src/redux/store.ts index 54dfe58c4..11bba3876 100644 --- a/packages/instant/src/redux/store.ts +++ b/packages/instant/src/redux/store.ts @@ -1,6 +1,6 @@ import * as _ from 'lodash'; import { applyMiddleware, createStore, Store as ReduxStore } from 'redux'; -import { composeWithDevTools, devToolsEnhancer } from 'redux-devtools-extension/developmentOnly'; +import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly'; import { analyticsMiddleware } from './analytics_middleware'; import { createReducer, State } from './reducer'; diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 2f2c221b1..6d3c75ea7 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -1,5 +1,4 @@ import { ObjectMap } from '@0x/types'; -import { logUtils } from '@0x/utils'; import { HEAP_ANALYTICS_DEVELOPMENT_APP_ID } from '../constants'; -- cgit v1.2.3 From ed26f5af985239e0dd91b68d4ec0aa264267acd6 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Thu, 15 Nov 2018 13:54:35 -0800 Subject: Move variable assignments around to be more clear --- packages/instant/src/redux/analytics_middleware.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 2b3ebf529..eddeeb193 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -12,11 +12,13 @@ import { State } from './reducer'; export const analyticsMiddleware: Middleware = store => next => middlewareAction => { const prevState = store.getState() as State; + const prevAccount = prevState.providerState.account; + const nextAction = next(middlewareAction) as Action; - const nextState = store.getState() as State; - const curAccount = nextState.providerState.account; - const prevAccount = prevState.providerState.account; + const curState = store.getState() as State; + const curAccount = curState.providerState.account; + switch (nextAction.type) { case ActionTypes.SET_ACCOUNT_STATE_READY: if (curAccount.state === AccountState.Ready && !_.isEqual(curAccount, prevAccount)) { -- cgit v1.2.3 From 37d60dc39ea6476c3185e124175cb02d5e830250 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 08:51:41 -0800 Subject: Typesafe analytic actions --- .../src/components/zero_ex_instant_provider.tsx | 3 +- packages/instant/src/redux/analytics_middleware.ts | 6 ++- packages/instant/src/util/analytics.ts | 50 +++++++++++----------- packages/instant/src/util/heap.ts | 19 +++++++- 4 files changed, 50 insertions(+), 28 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index cfc542a59..77adca472 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -19,6 +19,7 @@ import { gasPriceEstimator } from '../util/gas_price_estimator'; import { Heartbeater } from '../util/heartbeater'; import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory'; import { providerStateFactory } from '../util/provider_state_factory'; +import { analyticsMiddleware } from '../redux/analytics_middleware'; fonts.include(); @@ -129,7 +130,7 @@ export class ZeroExInstantProvider extends React.Component next => middlewareAction switch (nextAction.type) { case ActionTypes.SET_ACCOUNT_STATE_READY: - if (curAccount.state === AccountState.Ready && !_.isEqual(curAccount, prevAccount)) { + if (curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready) { const ethAddress = curAccount.address; analytics.addUserProperties({ ethAddress }); - analytics.track('Wallet - Ready'); + analytics.walletReady({ + numAssetsAvailable: curState.availableAssets ? curState.availableAssets.length : 0, + }); } break; case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index dd595529d..30193839e 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,35 +1,37 @@ import { ObjectMap } from '@0x/types'; -import { logUtils } from '@0x/utils'; -import { ANALYTICS_ENABLED } from '../constants'; +import { heapUtil } from './heap'; -import { HeapAnalytics, heapUtil } from './heap'; - -const evaluteHeapCall = (heapFunctionCall: (heap: HeapAnalytics) => void): void => { - if (!ANALYTICS_ENABLED) { - return; - } - - const curHeap = heapUtil.getHeap(); - if (curHeap) { - try { - heapFunctionCall(curHeap); - } catch (e) { - // We never want analytics to crash our React component - // TODO: error reporter here - logUtils.log('Analytics error', e); - } - } +enum EventNames { + WALLET_OPENED = 'Wallet - Opened', + WALLET_READY = 'Wallet - Ready', + WIDGET_OPENED = 'Widget - Opened', +} +const track = (eventName: EventNames, eventData: ObjectMap = {}): void => { + heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventData)); }; +function trackingEventFnWithoutPayload(eventName: EventNames): () => void { + return () => { + track(eventName); + }; +} +function trackingEventFnWithPayload>( + eventName: EventNames, +): (eventDataProperties: T) => void { + return (eventDataProperties: T) => { + track(eventName, eventDataProperties); + }; +} export const analytics = { + // TODO(sk): make these more specific addUserProperties: (properties: ObjectMap): void => { - evaluteHeapCall(heap => heap.addUserProperties(properties)); + heapUtil.evaluateHeapCall(heap => heap.addUserProperties(properties)); }, addEventProperties: (properties: ObjectMap): void => { - evaluteHeapCall(heap => heap.addEventProperties(properties)); - }, - track: (eventName: string, eventProperties?: ObjectMap): void => { - evaluteHeapCall(heap => heap.track(eventName, eventProperties)); + heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); }, + walletOpened: trackingEventFnWithoutPayload(EventNames.WALLET_OPENED), + walletReady: trackingEventFnWithPayload<{ numAssetsAvailable: number }>(EventNames.WALLET_READY), + widgetOpened: trackingEventFnWithoutPayload(EventNames.WIDGET_OPENED), }; diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 6d3c75ea7..5fd61b4c9 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -1,6 +1,7 @@ import { ObjectMap } from '@0x/types'; +import { logUtils } from '@0x/utils'; -import { HEAP_ANALYTICS_DEVELOPMENT_APP_ID } from '../constants'; +import { ANALYTICS_ENABLED, HEAP_ANALYTICS_DEVELOPMENT_APP_ID } from '../constants'; export interface HeapAnalytics { loaded: boolean; @@ -82,4 +83,20 @@ export const heapUtil = { return setupZeroExInstantHeap(); }, + evaluateHeapCall: (heapFunctionCall: (heap: HeapAnalytics) => void): void => { + if (!ANALYTICS_ENABLED) { + return; + } + + const curHeap = heapUtil.getHeap(); + if (curHeap) { + try { + heapFunctionCall(curHeap); + } catch (e) { + // We never want analytics to crash our React component + // TODO: error reporter here + logUtils.log('Analytics error', e); + } + } + }, }; -- cgit v1.2.3 From df71dba8edcba5ca5731bed969748bdcc73efe92 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 09:16:20 -0800 Subject: Make user and event properties more specific --- packages/instant/src/util/analytics.ts | 15 ++++++++++++--- packages/instant/src/util/heap.ts | 6 ++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 30193839e..92f717f7b 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -23,12 +23,21 @@ function trackingEventFnWithPayload>( }; } +export interface AnalyticsUserOptions { + ethAddress?: string; + ethBalanceInUnitAmount?: string; +} +export interface AnalyticsEventOptions { + embeddedHost?: string; + embeddedUrl?: string; + networkId: number; + providerName: string; +} export const analytics = { - // TODO(sk): make these more specific - addUserProperties: (properties: ObjectMap): void => { + addUserProperties: (properties: AnalyticsUserOptions): void => { heapUtil.evaluateHeapCall(heap => heap.addUserProperties(properties)); }, - addEventProperties: (properties: ObjectMap): void => { + addEventProperties: (properties: AnalyticsEventOptions): void => { heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); }, walletOpened: trackingEventFnWithoutPayload(EventNames.WALLET_OPENED), diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 5fd61b4c9..e697562e4 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -3,13 +3,15 @@ import { logUtils } from '@0x/utils'; import { ANALYTICS_ENABLED, HEAP_ANALYTICS_DEVELOPMENT_APP_ID } from '../constants'; +import { AnalyticsEventOptions, AnalyticsUserOptions } from './analytics'; + export interface HeapAnalytics { loaded: boolean; identify(id: string, idType: string): void; track(eventName: string, eventProperties?: ObjectMap): void; resetIdentity(): void; - addUserProperties(properties: ObjectMap): void; - addEventProperties(properties: ObjectMap): void; + addUserProperties(properties: AnalyticsUserOptions): void; + addEventProperties(properties: AnalyticsEventOptions): void; removeEventProperty(property: string): void; clearEventProperties(): void; } -- cgit v1.2.3 From 3add465edb779587e2b4bb136d8668b00b58a8fb Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 09:20:44 -0800 Subject: We may not know num available assets available when wallet ready, so not trackin there --- packages/instant/src/redux/analytics_middleware.ts | 4 +--- packages/instant/src/util/analytics.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 81031eb29..fb6d7eff1 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -24,9 +24,7 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction if (curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready) { const ethAddress = curAccount.address; analytics.addUserProperties({ ethAddress }); - analytics.walletReady({ - numAssetsAvailable: curState.availableAssets ? curState.availableAssets.length : 0, - }); + analytics.walletReady(); } break; case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 92f717f7b..ab8a86f04 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -41,6 +41,6 @@ export const analytics = { heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); }, walletOpened: trackingEventFnWithoutPayload(EventNames.WALLET_OPENED), - walletReady: trackingEventFnWithPayload<{ numAssetsAvailable: number }>(EventNames.WALLET_READY), + walletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), widgetOpened: trackingEventFnWithoutPayload(EventNames.WIDGET_OPENED), }; -- cgit v1.2.3 From 45a1899eade34e90801e3fbcba9a6789e43684f4 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 10:10:43 -0800 Subject: Add access to environment variables --- packages/instant/webpack.config.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js index 78a33ce90..129092d70 100644 --- a/packages/instant/webpack.config.js +++ b/packages/instant/webpack.config.js @@ -1,6 +1,15 @@ +const childProcess = require('child_process'); const path = require('path'); +const webpack = require('webpack'); + // The common js bundle (not this one) is built using tsc. // The umd bundle (this one) has a different entrypoint. + +const GIT_SHA = childProcess + .execSync('git rev-parse HEAD') + .toString() + .trim(); + module.exports = { entry: './src/index.umd.ts', output: { @@ -9,6 +18,15 @@ module.exports = { library: 'zeroExInstant', libraryTarget: 'umd', }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { + NODE_ENV: JSON.stringify(process.env.NODE_ENV), + GIT_SHA: JSON.stringify(GIT_SHA), + ENABLE_HEAP: process.env.ENABLE_HEAP, + }, + }), + ], devtool: 'source-map', resolve: { extensions: ['.js', '.json', '.ts', '.tsx'], -- cgit v1.2.3 From db7f74f99f7790297e737165a0fc9742fe3daf06 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 10:10:55 -0800 Subject: Switch heap id on environment, and make sure app id is what we expect --- packages/instant/src/constants.ts | 3 ++- packages/instant/src/util/heap.ts | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index f46b0ca21..80c93c431 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -16,8 +16,9 @@ export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; -export const ANALYTICS_ENABLED = true; // TODO: change when we can switch on dev +export const ANALYTICS_ENABLED = process.env.NODE_ENV === 'production' || process.env.ENABLE_HEAP; export const HEAP_ANALYTICS_DEVELOPMENT_APP_ID = '507265531'; +export const HEAP_ANALYTICS_PRODUCTION_APP_ID = '2323640988'; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index e697562e4..88f65c1ab 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -1,12 +1,13 @@ import { ObjectMap } from '@0x/types'; import { logUtils } from '@0x/utils'; -import { ANALYTICS_ENABLED, HEAP_ANALYTICS_DEVELOPMENT_APP_ID } from '../constants'; +import { ANALYTICS_ENABLED, HEAP_ANALYTICS_DEVELOPMENT_APP_ID, HEAP_ANALYTICS_PRODUCTION_APP_ID } from '../constants'; import { AnalyticsEventOptions, AnalyticsUserOptions } from './analytics'; export interface HeapAnalytics { loaded: boolean; + appid: string; identify(id: string, idType: string): void; track(eventName: string, eventProperties?: ObjectMap): void; resetIdentity(): void; @@ -23,6 +24,13 @@ const getWindow = (): ModifiedWindow => { return window as ModifiedWindow; }; +const getHeapAppId = (): string => { + if (process.env.NODE_ENV === 'production') { + return HEAP_ANALYTICS_PRODUCTION_APP_ID; + } + return HEAP_ANALYTICS_DEVELOPMENT_APP_ID; +}; + const setupZeroExInstantHeap = () => { const curWindow = getWindow(); // Set property to specify that this is zeroEx's heap @@ -64,7 +72,7 @@ const setupZeroExInstantHeap = () => { (window as any).heap[p[c]] = o(p[c]); }); // TODO: use production heap id once environment utils merged - (window as any).heap.load(HEAP_ANALYTICS_DEVELOPMENT_APP_ID); + (window as any).heap.load(getHeapAppId()); /* tslint:enable */ return curWindow.heap as HeapAnalytics; @@ -93,6 +101,10 @@ export const heapUtil = { const curHeap = heapUtil.getHeap(); if (curHeap) { try { + if (curHeap.appid !== getHeapAppId()) { + // Integrator has included heap after us and reset the app id + return; + } heapFunctionCall(curHeap); } catch (e) { // We never want analytics to crash our React component -- cgit v1.2.3 From 74254636b4e9918eeb5dd8ccc238de8bba74585f Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 10:11:00 -0800 Subject: Remove unused import --- packages/instant/src/components/zero_ex_instant_provider.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 77adca472..8bcdc214e 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -19,7 +19,6 @@ import { gasPriceEstimator } from '../util/gas_price_estimator'; import { Heartbeater } from '../util/heartbeater'; import { generateAccountHeartbeater, generateBuyQuoteHeartbeater } from '../util/heartbeater_factory'; import { providerStateFactory } from '../util/provider_state_factory'; -import { analyticsMiddleware } from '../redux/analytics_middleware'; fonts.include(); -- cgit v1.2.3 From ed62271cdab1157313f9dfe82fb4640291eeb757 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 10:13:32 -0800 Subject: Take out old TODO --- packages/instant/src/util/heap.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 88f65c1ab..44af5a9b5 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -71,7 +71,6 @@ const setupZeroExInstantHeap = () => { ) (window as any).heap[p[c]] = o(p[c]); }); - // TODO: use production heap id once environment utils merged (window as any).heap.load(getHeapAppId()); /* tslint:enable */ -- cgit v1.2.3 From 988bb398bcab7153d662d301c5ddac929110e014 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 10:14:00 -0800 Subject: Add initials to TODO note --- packages/instant/src/util/heap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 44af5a9b5..8e9feb2fa 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -107,7 +107,7 @@ export const heapUtil = { heapFunctionCall(curHeap); } catch (e) { // We never want analytics to crash our React component - // TODO: error reporter here + // TODO(sk): error reporter here logUtils.log('Analytics error', e); } } -- cgit v1.2.3 From 85a99203d0e85698aaaee25cdbf516175f1cb6e0 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 10:14:42 -0800 Subject: null -> undefined --- packages/instant/src/util/heap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 8e9feb2fa..1871c4abc 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -78,11 +78,11 @@ const setupZeroExInstantHeap = () => { }; export const heapUtil = { - getHeap: (): HeapAnalytics | null => { + getHeap: (): HeapAnalytics | undefined => { const curWindow = getWindow(); const hasOtherExistingHeapIntegration = curWindow.heap && !curWindow.zeroExInstantLoadedHeap; if (hasOtherExistingHeapIntegration) { - return null; + return undefined; } const zeroExInstantHeapIntegration = curWindow.zeroExInstantLoadedHeap && curWindow.heap; -- cgit v1.2.3 From 42565869a452fcf2f498a3ff396f76c43aadfa29 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 10:19:16 -0800 Subject: Report on git sha and npm version of build --- packages/instant/src/components/zero_ex_instant_provider.tsx | 2 ++ packages/instant/src/util/analytics.ts | 6 ++++-- packages/instant/webpack.config.js | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 8bcdc214e..e85efb422 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -128,6 +128,8 @@ export class ZeroExInstantProvider extends React.Component { diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js index 129092d70..43c149b3e 100644 --- a/packages/instant/webpack.config.js +++ b/packages/instant/webpack.config.js @@ -23,7 +23,8 @@ module.exports = { 'process.env': { NODE_ENV: JSON.stringify(process.env.NODE_ENV), GIT_SHA: JSON.stringify(GIT_SHA), - ENABLE_HEAP: process.env.ENABLE_HEAP, + ENABLE_HEAP: JSON.stringify(process.env.ENABLE_HEAP), + NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version), }, }), ], -- cgit v1.2.3 From cbcb954c3015b7044e0c1f1b594103df8ea4dfa7 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 10:21:51 -0800 Subject: Disable tslint for unused function so we can include this for future tracking events --- packages/instant/src/util/analytics.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e7a67bee5..e5f3635f2 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -15,6 +15,7 @@ function trackingEventFnWithoutPayload(eventName: EventNames): () => void { track(eventName); }; } +// tslint:disable-next-line:no-unused-variable function trackingEventFnWithPayload>( eventName: EventNames, ): (eventDataProperties: T) => void { -- cgit v1.2.3 From 21ae0c46e1b0c0b4ba3f73cc2b58d0c430bf9043 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 14:51:57 -0800 Subject: Move ip import back --- packages/instant/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js index ccbbe7359..6a4953bcc 100644 --- a/packages/instant/webpack.config.js +++ b/packages/instant/webpack.config.js @@ -1,4 +1,5 @@ const childProcess = require('child_process'); +const ip = require('ip'); const path = require('path'); const webpack = require('webpack'); @@ -9,7 +10,6 @@ const GIT_SHA = childProcess .execSync('git rev-parse HEAD') .toString() .trim(); -const ip = require('ip'); const config = { entry: './src/index.umd.ts', output: { -- cgit v1.2.3 From 31ffa65f59fc6d2c6c7f79c1ac0e2abe0c5ed4ab Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 15:06:11 -0800 Subject: Getting rid of unused function, and using track prefix --- packages/instant/src/components/zero_ex_instant_provider.tsx | 2 +- packages/instant/src/redux/analytics_middleware.ts | 2 +- packages/instant/src/util/analytics.ts | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 5fa64aa45..74e42bb40 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -132,7 +132,7 @@ export class ZeroExInstantProvider extends React.Component next => middlewareAction if (curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready) { const ethAddress = curAccount.address; analytics.addUserProperties({ ethAddress }); - analytics.walletReady(); + analytics.trackWalletReady(); } break; case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE: diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index e5f3635f2..b75665ff5 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -3,7 +3,6 @@ import { ObjectMap } from '@0x/types'; import { heapUtil } from './heap'; enum EventNames { - WALLET_OPENED = 'Wallet - Opened', WALLET_READY = 'Wallet - Ready', WIDGET_OPENED = 'Widget - Opened', } @@ -43,7 +42,6 @@ export const analytics = { addEventProperties: (properties: AnalyticsEventOptions): void => { heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); }, - walletOpened: trackingEventFnWithoutPayload(EventNames.WALLET_OPENED), - walletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), - widgetOpened: trackingEventFnWithoutPayload(EventNames.WIDGET_OPENED), + trackWalletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), + trackWidgetOpened: trackingEventFnWithoutPayload(EventNames.WIDGET_OPENED), }; -- cgit v1.2.3 From 4d7bd15334f909765749fea1c67ad26b161d6025 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 15:25:29 -0800 Subject: Trigger Wallet Ready when address changed --- packages/instant/src/redux/analytics_middleware.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index 7fbb12cb9..a86cf1b83 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -3,13 +3,27 @@ import * as _ from 'lodash'; import { Middleware } from 'redux'; import { ETH_DECIMALS } from '../constants'; -import { AccountState } from '../types'; +import { Account, AccountState } from '../types'; import { analytics } from '../util/analytics'; import { Action, ActionTypes } from './actions'; import { State } from './reducer'; +const shouldTriggerWalletReady = (prevAccount: Account, curAccount: Account): boolean => { + const justTurnedReady = curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready; + if (justTurnedReady) { + return true; + } + + if (curAccount.state === AccountState.Ready && prevAccount.state === AccountState.Ready) { + // Account was ready, and is now ready again, but address has changed + return curAccount.address !== prevAccount.address; + } + + return false; +}; + export const analyticsMiddleware: Middleware = store => next => middlewareAction => { const prevState = store.getState() as State; const prevAccount = prevState.providerState.account; @@ -21,7 +35,7 @@ export const analyticsMiddleware: Middleware = store => next => middlewareAction switch (nextAction.type) { case ActionTypes.SET_ACCOUNT_STATE_READY: - if (curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready) { + if (curAccount.state === AccountState.Ready && shouldTriggerWalletReady(prevAccount, curAccount)) { const ethAddress = curAccount.address; analytics.addUserProperties({ ethAddress }); analytics.trackWalletReady(); -- cgit v1.2.3 From e8be70da10c887956d6e200f7d551d3d7bbafb93 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 15:29:07 -0800 Subject: Widget -> Instant --- packages/instant/src/components/zero_ex_instant_provider.tsx | 2 +- packages/instant/src/util/analytics.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 74e42bb40..1d5e7fe6f 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -132,7 +132,7 @@ export class ZeroExInstantProvider extends React.Component Date: Fri, 16 Nov 2018 15:29:59 -0800 Subject: Remove old function --- packages/instant/src/util/analytics.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 4c229be03..1667c246c 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -5,7 +5,6 @@ import { heapUtil } from './heap'; enum EventNames { INSTANT_OPENED = 'Instant - Opened', WALLET_READY = 'Wallet - Ready', - WIDGET_OPENED = 'Widget - Opened', } const track = (eventName: EventNames, eventData: ObjectMap = {}): void => { heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventData)); @@ -44,6 +43,5 @@ export const analytics = { heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); }, trackWalletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), - trackWidgetOpened: trackingEventFnWithoutPayload(EventNames.WIDGET_OPENED), trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), }; -- cgit v1.2.3 From 1564415e5dc29cd76ac17f679ed83e0973764153 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 15:41:54 -0800 Subject: Specify fallback web3 provider in analytics --- packages/instant/src/constants.ts | 1 + packages/instant/src/types.ts | 1 + packages/instant/src/util/env.ts | 2 ++ packages/instant/src/util/provider_factory.ts | 4 ++++ 4 files changed, 8 insertions(+) diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 80c93c431..26d5ff436 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -50,4 +50,5 @@ export const PROVIDER_TYPE_TO_NAME: { [key in ProviderType]: string } = { [ProviderType.Mist]: 'Mist', [ProviderType.CoinbaseWallet]: 'Coinbase Wallet', [ProviderType.Parity]: 'Parity', + [ProviderType.Fallback]: 'Fallback', }; diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts index 67f21a396..31162e471 100644 --- a/packages/instant/src/types.ts +++ b/packages/instant/src/types.ts @@ -164,4 +164,5 @@ export enum ProviderType { Mist = 'MIST', CoinbaseWallet = 'COINBASE_WALLET', Cipher = 'CIPHER', + Fallback = 'FALLBACK', } diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts index 4a32f9cb1..59b47d1e3 100644 --- a/packages/instant/src/util/env.ts +++ b/packages/instant/src/util/env.ts @@ -52,6 +52,8 @@ export const envUtil = { return ProviderType.CoinbaseWallet; } else if (!_.isUndefined(_.get(window, '__CIPHER__'))) { return ProviderType.Cipher; + } else if ((provider as any).zeroExInstantFallbackEngine) { + return ProviderType.Fallback; } return; }, diff --git a/packages/instant/src/util/provider_factory.ts b/packages/instant/src/util/provider_factory.ts index 603f7674d..d77407521 100644 --- a/packages/instant/src/util/provider_factory.ts +++ b/packages/instant/src/util/provider_factory.ts @@ -29,6 +29,10 @@ export const providerFactory = { providerEngine.addProvider(new RPCSubprovider(rpcUrl)); // // Start the Provider Engine providerEngine.start(); + // This feels a bit dirty, but was the only way I could think of + // checking to see if this engine is our fallback engine, and not + // another Web3Provider engine provided by some dapp browser + (providerEngine as any).zeroExInstantFallbackEngine = true; return providerEngine; }, }; -- cgit v1.2.3 From 097bfe581dff6ff77e3cf19a03138743ae13868e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 16:21:38 -0800 Subject: Better way of reporting Fallback provider --- packages/instant/src/util/env.ts | 2 -- packages/instant/src/util/provider_factory.ts | 4 ---- packages/instant/src/util/provider_state_factory.ts | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts index 59b47d1e3..4a32f9cb1 100644 --- a/packages/instant/src/util/env.ts +++ b/packages/instant/src/util/env.ts @@ -52,8 +52,6 @@ export const envUtil = { return ProviderType.CoinbaseWallet; } else if (!_.isUndefined(_.get(window, '__CIPHER__'))) { return ProviderType.Cipher; - } else if ((provider as any).zeroExInstantFallbackEngine) { - return ProviderType.Fallback; } return; }, diff --git a/packages/instant/src/util/provider_factory.ts b/packages/instant/src/util/provider_factory.ts index d77407521..603f7674d 100644 --- a/packages/instant/src/util/provider_factory.ts +++ b/packages/instant/src/util/provider_factory.ts @@ -29,10 +29,6 @@ export const providerFactory = { providerEngine.addProvider(new RPCSubprovider(rpcUrl)); // // Start the Provider Engine providerEngine.start(); - // This feels a bit dirty, but was the only way I could think of - // checking to see if this engine is our fallback engine, and not - // another Web3Provider engine provided by some dapp browser - (providerEngine as any).zeroExInstantFallbackEngine = true; return providerEngine; }, }; diff --git a/packages/instant/src/util/provider_state_factory.ts b/packages/instant/src/util/provider_state_factory.ts index 452a71460..7c788dff2 100644 --- a/packages/instant/src/util/provider_state_factory.ts +++ b/packages/instant/src/util/provider_state_factory.ts @@ -56,7 +56,7 @@ export const providerStateFactory = { getInitialProviderStateFallback: (orderSource: OrderSource, network: Network): ProviderState => { const provider = providerFactory.getFallbackNoSigningProvider(network); const providerState: ProviderState = { - name: envUtil.getProviderName(provider), + name: 'Fallback', provider, web3Wrapper: new Web3Wrapper(provider), assetBuyer: assetBuyerFactory.getAssetBuyer(provider, orderSource, network), -- cgit v1.2.3 From 3f0d94c83872ae80d6377fd4f712efa4c174a284 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Fri, 16 Nov 2018 16:44:23 -0800 Subject: Add way to disable via props --- .../src/components/zero_ex_instant_provider.tsx | 6 +++++- packages/instant/src/util/analytics.ts | 23 +++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 1d5e7fe6f..52454148f 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -12,7 +12,7 @@ import { DEFAULT_STATE, DefaultState, State } from '../redux/reducer'; import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; import { AccountState, AffiliateInfo, AssetMetaData, Network, OrderSource } from '../types'; -import { analytics } from '../util/analytics'; +import { analytics, disableAnalytics } from '../util/analytics'; import { assetUtils } from '../util/asset'; import { errorFlasher } from '../util/error_flasher'; import { gasPriceEstimator } from '../util/gas_price_estimator'; @@ -37,6 +37,7 @@ export interface ZeroExInstantProviderOptionalProps { additionalAssetMetaDataMap: ObjectMap; networkId: Network; affiliateInfo: AffiliateInfo; + disableAnalyticsTracking: boolean; } export class ZeroExInstantProvider extends React.Component { @@ -124,6 +125,9 @@ export class ZeroExInstantProvider extends React.Component { + disabled = true; +}; +export const evaluateIfEnabled = (fnCall: () => void) => { + if (disabled) { + return; + } + fnCall(); +}; + enum EventNames { INSTANT_OPENED = 'Instant - Opened', WALLET_READY = 'Wallet - Ready', } const track = (eventName: EventNames, eventData: ObjectMap = {}): void => { - heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventData)); + evaluateIfEnabled(() => { + heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventData)); + }); }; function trackingEventFnWithoutPayload(eventName: EventNames): () => void { return () => { @@ -37,10 +50,14 @@ export interface AnalyticsEventOptions { } export const analytics = { addUserProperties: (properties: AnalyticsUserOptions): void => { - heapUtil.evaluateHeapCall(heap => heap.addUserProperties(properties)); + evaluateIfEnabled(() => { + heapUtil.evaluateHeapCall(heap => heap.addUserProperties(properties)); + }); }, addEventProperties: (properties: AnalyticsEventOptions): void => { - heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); + evaluateIfEnabled(() => { + heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties)); + }); }, trackWalletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY), trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED), -- cgit v1.2.3 From e23f90b82cc1346bea66e91858bc7fdc874542dd Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 09:48:34 -0800 Subject: No need to explicit send in NODE_ENV --- packages/instant/webpack.config.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js index ce4f1672e..fe3e158a0 100644 --- a/packages/instant/webpack.config.js +++ b/packages/instant/webpack.config.js @@ -25,7 +25,6 @@ const config = { plugins: [ new webpack.DefinePlugin({ 'process.env': { - NODE_ENV: JSON.stringify(process.env.NODE_ENV), GIT_SHA: JSON.stringify(GIT_SHA), ENABLE_HEAP: JSON.stringify(process.env.ENABLE_HEAP), NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version), -- cgit v1.2.3 From 2bfd03e64f20905b0526d65813f78eff3e924727 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 09:54:59 -0800 Subject: Change disabled analytics name, add assertion, and always set --- packages/instant/src/components/zero_ex_instant_provider.tsx | 6 ++---- packages/instant/src/index.umd.ts | 3 +++ packages/instant/src/util/analytics.ts | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 52454148f..9435d8c7c 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -37,7 +37,7 @@ export interface ZeroExInstantProviderOptionalProps { additionalAssetMetaDataMap: ObjectMap; networkId: Network; affiliateInfo: AffiliateInfo; - disableAnalyticsTracking: boolean; + shouldDisableAnalyticsTracking: boolean; } export class ZeroExInstantProvider extends React.Component { @@ -125,9 +125,7 @@ export class ZeroExInstantProvider extends React.Component { - disabled = true; +let isDisabled = false; +export const disableAnalytics = (shouldDisableAnalytics: boolean) => { + isDisabled = shouldDisableAnalytics; }; export const evaluateIfEnabled = (fnCall: () => void) => { - if (disabled) { + if (isDisabled) { return; } fnCall(); -- cgit v1.2.3 From 8772d916993d754f784d7435dbbfb60c9a6f9205 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 12:02:31 -0800 Subject: Get heap analytics id from ENV variable --- packages/instant/src/constants.ts | 4 +- packages/instant/src/util/heap.ts | 18 +++---- packages/instant/webpack.config.js | 108 ++++++++++++++++++++++--------------- 3 files changed, 73 insertions(+), 57 deletions(-) diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 26d5ff436..44d09e31e 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -16,9 +16,7 @@ export const BUY_QUOTE_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 15; export const DEFAULT_GAS_PRICE = GWEI_IN_WEI.mul(6); export const DEFAULT_ESTIMATED_TRANSACTION_TIME_MS = ONE_MINUTE_MS * 2; export const ETH_GAS_STATION_API_BASE_URL = 'https://ethgasstation.info'; -export const ANALYTICS_ENABLED = process.env.NODE_ENV === 'production' || process.env.ENABLE_HEAP; -export const HEAP_ANALYTICS_DEVELOPMENT_APP_ID = '507265531'; -export const HEAP_ANALYTICS_PRODUCTION_APP_ID = '2323640988'; +export const HEAP_ANALYTICS_ID = process.env.HEAP_ANALYTICS_ID; export const COINBASE_API_BASE_URL = 'https://api.coinbase.com/v2'; export const PROGRESS_STALL_AT_WIDTH = '95%'; export const PROGRESS_FINISH_ANIMATION_TIME_MS = 200; diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts index 1871c4abc..78ec3b3cc 100644 --- a/packages/instant/src/util/heap.ts +++ b/packages/instant/src/util/heap.ts @@ -1,7 +1,8 @@ import { ObjectMap } from '@0x/types'; import { logUtils } from '@0x/utils'; +import * as _ from 'lodash'; -import { ANALYTICS_ENABLED, HEAP_ANALYTICS_DEVELOPMENT_APP_ID, HEAP_ANALYTICS_PRODUCTION_APP_ID } from '../constants'; +import { HEAP_ANALYTICS_ID } from '../constants'; import { AnalyticsEventOptions, AnalyticsUserOptions } from './analytics'; @@ -24,14 +25,11 @@ const getWindow = (): ModifiedWindow => { return window as ModifiedWindow; }; -const getHeapAppId = (): string => { - if (process.env.NODE_ENV === 'production') { - return HEAP_ANALYTICS_PRODUCTION_APP_ID; +const setupZeroExInstantHeap = () => { + if (_.isUndefined(HEAP_ANALYTICS_ID)) { + return; } - return HEAP_ANALYTICS_DEVELOPMENT_APP_ID; -}; -const setupZeroExInstantHeap = () => { const curWindow = getWindow(); // Set property to specify that this is zeroEx's heap curWindow.zeroExInstantLoadedHeap = true; @@ -71,7 +69,7 @@ const setupZeroExInstantHeap = () => { ) (window as any).heap[p[c]] = o(p[c]); }); - (window as any).heap.load(getHeapAppId()); + (window as any).heap.load(HEAP_ANALYTICS_ID); /* tslint:enable */ return curWindow.heap as HeapAnalytics; @@ -93,14 +91,14 @@ export const heapUtil = { return setupZeroExInstantHeap(); }, evaluateHeapCall: (heapFunctionCall: (heap: HeapAnalytics) => void): void => { - if (!ANALYTICS_ENABLED) { + if (_.isUndefined(HEAP_ANALYTICS_ID)) { return; } const curHeap = heapUtil.getHeap(); if (curHeap) { try { - if (curHeap.appid !== getHeapAppId()) { + if (curHeap.appid !== HEAP_ANALYTICS_ID) { // Integrator has included heap after us and reset the app id return; } diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js index fe3e158a0..7ffb09754 100644 --- a/packages/instant/webpack.config.js +++ b/packages/instant/webpack.config.js @@ -11,50 +11,70 @@ const GIT_SHA = childProcess .toString() .trim(); -const outputPath = process.env.WEBPACK_OUTPUT_PATH || 'umd'; -const config = { - entry: { - instant: './src/index.umd.ts', - }, - output: { - filename: '[name].js', - path: path.resolve(__dirname, outputPath), - library: 'zeroExInstant', - libraryTarget: 'umd', - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env': { - GIT_SHA: JSON.stringify(GIT_SHA), - ENABLE_HEAP: JSON.stringify(process.env.ENABLE_HEAP), - NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version), - }, - }), - ], - devtool: 'source-map', - resolve: { - extensions: ['.js', '.json', '.ts', '.tsx'], - }, - module: { - rules: [ - { - test: /\.(ts|tsx)$/, - loader: 'awesome-typescript-loader', - }, +const HEAP_PRODUCTION_ENV_VAR_NAME = 'INSTANT_HEAP_ANALYTICS_ID_PRODUCTION'; +const HEAP_DEVELOPMENT_ENV_VAR_NAME = 'INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT'; +const getHeapAnalyticsId = modeName => { + if (modeName === 'production') { + if (process.env[HEAP_PRODUCTION_ENV_VAR_NAME]) { + return process.env[HEAP_PRODUCTION_ENV_VAR_NAME]; + } + throw new Error(`Must have ${HEAP_PRODUCTION_ENV_VAR_NAME} set`); + } + + if (modeName === 'development') { + return process.env[HEAP_DEVELOPMENT_ENV_VAR_NAME]; + } + + return undefined; +}; + +module.exports = (env, argv) => { + const outputPath = process.env.WEBPACK_OUTPUT_PATH || 'umd'; + const config = { + entry: { + instant: './src/index.umd.ts', + }, + output: { + filename: '[name].js', + path: path.resolve(__dirname, outputPath), + library: 'zeroExInstant', + libraryTarget: 'umd', + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { + GIT_SHA: JSON.stringify(GIT_SHA), + HEAP_ANALYTICS_ID: getHeapAnalyticsId(argv.mode), + NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version), + }, + }), ], - }, - devServer: { - contentBase: path.join(__dirname, 'public'), - port: 5000, - host: '0.0.0.0', - after: () => { - if (config.devServer.host === '0.0.0.0') { - console.log( - `webpack-dev-server can be accessed externally at: http://${ip.address()}:${config.devServer.port}`, - ); - } + devtool: 'source-map', + resolve: { + extensions: ['.js', '.json', '.ts', '.tsx'], + }, + module: { + rules: [ + { + test: /\.(ts|tsx)$/, + loader: 'awesome-typescript-loader', + }, + ], }, - }, + devServer: { + contentBase: path.join(__dirname, 'public'), + port: 5000, + host: '0.0.0.0', + after: () => { + if (config.devServer.host === '0.0.0.0') { + console.log( + `webpack-dev-server can be accessed externally at: http://${ip.address()}:${ + config.devServer.port + }`, + ); + } + }, + }, + }; + return config; }; - -module.exports = config; -- cgit v1.2.3 From 1880c7c27ddf3ba1b5e722f396126d5ff28e79a6 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 12:14:27 -0800 Subject: Linting: rename variable --- packages/instant/src/redux/analytics_middleware.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts index a86cf1b83..f971dbd33 100644 --- a/packages/instant/src/redux/analytics_middleware.ts +++ b/packages/instant/src/redux/analytics_middleware.ts @@ -11,8 +11,8 @@ import { Action, ActionTypes } from './actions'; import { State } from './reducer'; const shouldTriggerWalletReady = (prevAccount: Account, curAccount: Account): boolean => { - const justTurnedReady = curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready; - if (justTurnedReady) { + const didJustTurnReady = curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready; + if (didJustTurnReady) { return true; } -- cgit v1.2.3 From 497385818b42f298c777ce3fbeb3e2d55a2bdc64 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 15:38:09 -0800 Subject: Check for instant heap production credentials in pre-publish step --- packages/instant/webpack.config.js | 5 +---- packages/monorepo-scripts/src/prepublish_checks.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js index 7139ced16..41276809c 100644 --- a/packages/instant/webpack.config.js +++ b/packages/instant/webpack.config.js @@ -15,10 +15,7 @@ const HEAP_PRODUCTION_ENV_VAR_NAME = 'INSTANT_HEAP_ANALYTICS_ID_PRODUCTION'; const HEAP_DEVELOPMENT_ENV_VAR_NAME = 'INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT'; const getHeapAnalyticsId = modeName => { if (modeName === 'production') { - if (process.env[HEAP_PRODUCTION_ENV_VAR_NAME]) { - return process.env[HEAP_PRODUCTION_ENV_VAR_NAME]; - } - throw new Error(`Must have ${HEAP_PRODUCTION_ENV_VAR_NAME} set`); + return process.env[HEAP_PRODUCTION_ENV_VAR_NAME]; } if (modeName === 'development') { diff --git a/packages/monorepo-scripts/src/prepublish_checks.ts b/packages/monorepo-scripts/src/prepublish_checks.ts index 5f603ebc7..fc550cf3a 100644 --- a/packages/monorepo-scripts/src/prepublish_checks.ts +++ b/packages/monorepo-scripts/src/prepublish_checks.ts @@ -17,6 +17,7 @@ async function prepublishChecksAsync(): Promise { await checkChangelogFormatAsync(updatedPublicPackages); await checkGitTagsForNextVersionAndDeleteIfExistAsync(updatedPublicPackages); await checkPublishRequiredSetupAsync(); + checkRequiredEnvVariables(); } async function checkGitTagsForNextVersionAndDeleteIfExistAsync(updatedPublicPackages: Package[]): Promise { @@ -183,6 +184,16 @@ async function checkPublishRequiredSetupAsync(): Promise { } } +const checkRequiredEnvVariables = () => { + utils.log('Checking required environment variables...'); + const requiredEnvVars = ['INSTANT_HEAP_ANALYTICS_ID_PRODUCTION']; + requiredEnvVars.forEach(requiredEnvVarName => { + if (_.isUndefined(process.env[requiredEnvVarName])) { + throw new Error(`Must have ${requiredEnvVarName} set`); + } + }); +}; + prepublishChecksAsync().catch(err => { utils.log(err.message); process.exit(1); -- cgit v1.2.3 From 578a46c57f04bbae223fe0b6b79f6aaa28576a95 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 16:28:40 -0800 Subject: feat(instant): Add powered by 0x image --- packages/instant/src/assets/powered_by_0x.svg | 27 ++++++++++++++++++++++ .../src/components/zero_ex_instant_container.tsx | 15 ++++++++++++ packages/instant/src/constants.ts | 1 + 3 files changed, 43 insertions(+) create mode 100644 packages/instant/src/assets/powered_by_0x.svg diff --git a/packages/instant/src/assets/powered_by_0x.svg b/packages/instant/src/assets/powered_by_0x.svg new file mode 100644 index 000000000..f49238a3c --- /dev/null +++ b/packages/instant/src/assets/powered_by_0x.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 698bfef17..9d5fe7171 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; +import { ZERO_EX_SITE_URL } from '../constants'; import { AvailableERC20TokenSelector } from '../containers/available_erc20_token_selector'; import { ConnectedBuyOrderProgressOrPaymentMethod } from '../containers/connected_buy_order_progress_or_payment_method'; import { CurrentStandardSlidingPanel } from '../containers/current_standard_sliding_panel'; @@ -15,6 +16,7 @@ import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; +import { Text } from './ui/text'; export interface ZeroExInstantContainerProps { orderProcessState: OrderProcessState; @@ -28,6 +30,8 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; public render(): React.ReactNode { + const PoweredByLogo = require('../assets/powered_by_0x.svg'); + return ( @@ -64,6 +68,17 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon + + + + + ); diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index 5bd2349b3..ad2d568fe 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -31,6 +31,7 @@ export const ETHEREUM_NODE_URL_BY_NETWORK = { [Network.Mainnet]: 'https://mainnet.infura.io/', [Network.Kovan]: 'https://kovan.infura.io/', }; +export const ZERO_EX_SITE_URL = 'https://www.0xproject.com/'; export const BLOCK_POLLING_INTERVAL_MS = 10000; // 10s export const NO_ACCOUNT: AccountNotReady = { state: AccountState.None, -- cgit v1.2.3 From a1b7f0ad83477f575bb047048f77c3c9639b8b8e Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 16:36:51 -0800 Subject: Use anchor instead of Text --- packages/instant/src/components/zero_ex_instant_container.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 9d5fe7171..1de3bbbbb 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -25,13 +25,12 @@ export interface ZeroExInstantContainerState { tokenSelectionPanelAnimationState: SlideAnimationState; } +const PoweredByLogo = require('../assets/powered_by_0x.svg'); export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantContainerState> { public state = { tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; public render(): React.ReactNode { - const PoweredByLogo = require('../assets/powered_by_0x.svg'); - return ( @@ -75,9 +74,9 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon marginRight="auto" width="140px" > - + - + -- cgit v1.2.3 From db6b2cbb05c59003bd2eee05d7a560949f8e15d9 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 16:38:56 -0800 Subject: Fix linting --- packages/instant/src/components/zero_ex_instant_container.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 1de3bbbbb..2e3fb3c87 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -16,7 +16,6 @@ import { CSSReset } from './css_reset'; import { SlidingPanel } from './sliding_panel'; import { Container } from './ui/container'; import { Flex } from './ui/flex'; -import { Text } from './ui/text'; export interface ZeroExInstantContainerProps { orderProcessState: OrderProcessState; @@ -25,12 +24,12 @@ export interface ZeroExInstantContainerState { tokenSelectionPanelAnimationState: SlideAnimationState; } -const PoweredByLogo = require('../assets/powered_by_0x.svg'); export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantContainerState> { public state = { tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; public render(): React.ReactNode { + const PoweredByLogo = require('../assets/powered_by_0x.svg'); return ( -- cgit v1.2.3 From e86982bd41b933a6929bbf571d246585ed3c3882 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 17:12:21 -0800 Subject: Add ability to import SVGs in TS --- packages/instant/src/globals.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/instant/src/globals.d.ts b/packages/instant/src/globals.d.ts index 94e63a32d..1b5fa443d 100644 --- a/packages/instant/src/globals.d.ts +++ b/packages/instant/src/globals.d.ts @@ -1,3 +1,9 @@ +declare module '*.svg' { + const content: any; + /* tslint:disable */ + export default content; + /* tslint:enable */ +} declare module '*.json' { const json: any; /* tslint:disable */ -- cgit v1.2.3 From 0ba34f587c58074a7448cec43894bfab764e4bc3 Mon Sep 17 00:00:00 2001 From: Steve Klebanoff Date: Mon, 19 Nov 2018 17:12:32 -0800 Subject: Import via TS --- packages/instant/src/components/zero_ex_instant_container.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index 2e3fb3c87..47c938472 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; +import PoweredByLogo from '../assets/powered_by_0x.svg'; import { ZERO_EX_SITE_URL } from '../constants'; import { AvailableERC20TokenSelector } from '../containers/available_erc20_token_selector'; import { ConnectedBuyOrderProgressOrPaymentMethod } from '../containers/connected_buy_order_progress_or_payment_method'; @@ -29,7 +30,6 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon tokenSelectionPanelAnimationState: 'none' as SlideAnimationState, }; public render(): React.ReactNode { - const PoweredByLogo = require('../assets/powered_by_0x.svg'); return ( -- cgit v1.2.3 From 22cfdd9f0b5cd2b8d53384e16defc956570ccd6a Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 20 Nov 2018 14:48:32 +0100 Subject: Properly unmarshall TransactionReceiptRPC to TransactionReceipt --- packages/web3-wrapper/CHANGELOG.json | 13 ++++++++++++ packages/web3-wrapper/package.json | 1 + packages/web3-wrapper/src/index.ts | 3 +++ packages/web3-wrapper/src/marshaller.ts | 18 +++++++++++++++++ packages/web3-wrapper/src/types.ts | 27 +++++++++++++++++++++++++ packages/web3-wrapper/src/web3_wrapper.ts | 26 ++++++++++++++---------- packages/web3-wrapper/test/web3_wrapper_test.ts | 14 ++++++++++++- 7 files changed, 90 insertions(+), 12 deletions(-) diff --git a/packages/web3-wrapper/CHANGELOG.json b/packages/web3-wrapper/CHANGELOG.json index b938f6986..cc65c2a7d 100644 --- a/packages/web3-wrapper/CHANGELOG.json +++ b/packages/web3-wrapper/CHANGELOG.json @@ -1,4 +1,17 @@ [ + { + "version": "3.1.5", + "changes": [ + { + "note": "Add unmarshalling of transaction receipts", + "pr": 1291 + }, + { + "note": "Return `undefined` instead of `null` if transaction receipt not found", + "pr": 1291 + } + ] + }, { "timestamp": 1542208198, "version": "3.1.4", diff --git a/packages/web3-wrapper/package.json b/packages/web3-wrapper/package.json index 2469f7627..8d4d7ec35 100644 --- a/packages/web3-wrapper/package.json +++ b/packages/web3-wrapper/package.json @@ -10,6 +10,7 @@ "scripts": { "build": "tsc -b", "build:ci": "yarn build", + "watch_without_deps": "tsc -w", "clean": "shx rm -rf lib generated_docs", "lint": "tslint --format stylish --project .", "test": "yarn run_mocha", diff --git a/packages/web3-wrapper/src/index.ts b/packages/web3-wrapper/src/index.ts index 679563a2b..4d20ba9be 100644 --- a/packages/web3-wrapper/src/index.ts +++ b/packages/web3-wrapper/src/index.ts @@ -52,6 +52,9 @@ export { CallDataRPC, BlockWithoutTransactionDataRPC, BlockWithTransactionDataRPC, + TransactionReceiptStatusRPC, + TransactionReceiptRPC, + LogEntryRPC, TransactionRPC, TxDataRPC, } from './types'; diff --git a/packages/web3-wrapper/src/marshaller.ts b/packages/web3-wrapper/src/marshaller.ts index 299c6a64c..7bd274c85 100644 --- a/packages/web3-wrapper/src/marshaller.ts +++ b/packages/web3-wrapper/src/marshaller.ts @@ -9,6 +9,7 @@ import { LogEntry, RawLogEntry, Transaction, + TransactionReceipt, TxData, } from 'ethereum-types'; import ethUtil = require('ethereumjs-util'); @@ -21,6 +22,7 @@ import { BlockWithTransactionDataRPC, CallDataRPC, CallTxDataBaseRPC, + TransactionReceiptRPC, TransactionRPC, TxDataRPC, } from './types'; @@ -91,6 +93,22 @@ export const marshaller = { }; return tx; }, + /** + * Unmarshall transaction receipt + * @param txReceiptRpc transaction receipt to unmarshall + * @return unmarshalled transaction receipt + */ + unmarshalTransactionReceipt(txReceiptRpc: TransactionReceiptRPC): TransactionReceipt { + const txReceipt = { + ...txReceiptRpc, + blockNumber: utils.convertHexToNumber(txReceiptRpc.blockNumber), + transactionIndex: utils.convertHexToNumber(txReceiptRpc.transactionIndex), + cumulativeGasUsed: utils.convertHexToNumber(txReceiptRpc.cumulativeGasUsed), + gasUsed: utils.convertHexToNumber(txReceiptRpc.gasUsed), + logs: _.map(txReceiptRpc.logs, marshaller.unmarshalLog.bind(marshaller)), + }; + return txReceipt; + }, /** * Unmarshall transaction data * @param txDataRpc transaction data to unmarshall diff --git a/packages/web3-wrapper/src/types.ts b/packages/web3-wrapper/src/types.ts index e81039186..eb5a35f07 100644 --- a/packages/web3-wrapper/src/types.ts +++ b/packages/web3-wrapper/src/types.ts @@ -41,6 +41,33 @@ export interface TransactionRPC { input: string; } +export interface TransactionReceiptRPC { + blockHash: string; + blockNumber: string; + transactionHash: string; + transactionIndex: string; + from: string; + to: string; + status: TransactionReceiptStatusRPC; + cumulativeGasUsed: string; + gasUsed: string; + contractAddress: string | null; + logs: LogEntryRPC[]; +} + +export interface LogEntryRPC { + logIndex: string | null; + transactionIndex: string | null; + transactionHash: string; + blockHash: string | null; + blockNumber: string | null; + address: string; + data: string; + topics: string[]; +} + +export type TransactionReceiptStatusRPC = null | string | 0 | 1; + export interface CallTxDataBaseRPC { to?: string; value?: string; diff --git a/packages/web3-wrapper/src/web3_wrapper.ts b/packages/web3-wrapper/src/web3_wrapper.ts index be1713f20..f1247e48a 100644 --- a/packages/web3-wrapper/src/web3_wrapper.ts +++ b/packages/web3-wrapper/src/web3_wrapper.ts @@ -27,6 +27,7 @@ import { BlockWithoutTransactionDataRPC, BlockWithTransactionDataRPC, NodeType, + TransactionReceiptRPC, TransactionRPC, Web3WrapperErrors, } from './types'; @@ -212,20 +213,23 @@ export class Web3Wrapper { return networkId; } /** - * Retrieves the transaction receipt for a given transaction hash + * Retrieves the transaction receipt for a given transaction hash if found * @param txHash Transaction hash - * @returns The transaction receipt, including it's status (0: failed, 1: succeeded or undefined: not found) + * @returns The transaction receipt, including it's status (0: failed, 1: succeeded). Returns undefined if transaction not found. */ - public async getTransactionReceiptAsync(txHash: string): Promise { + public async getTransactionReceiptIfExistsAsync(txHash: string): Promise { assert.isHexString('txHash', txHash); - const transactionReceipt = await this.sendRawPayloadAsync({ + const transactionReceiptRpc = await this.sendRawPayloadAsync({ method: 'eth_getTransactionReceipt', params: [txHash], }); - if (!_.isNull(transactionReceipt)) { - transactionReceipt.status = Web3Wrapper._normalizeTxReceiptStatus(transactionReceipt.status); + if (!_.isNull(transactionReceiptRpc)) { + transactionReceiptRpc.status = Web3Wrapper._normalizeTxReceiptStatus(transactionReceiptRpc.status); + const transactionReceipt = marshaller.unmarshalTransactionReceipt(transactionReceiptRpc); + return transactionReceipt; + } else { + return undefined; } - return transactionReceipt; } /** * Retrieves the transaction data for a given transaction @@ -572,8 +576,8 @@ export class Web3Wrapper { assert.isNumber('timeoutMs', timeoutMs); } // Immediately check if the transaction has already been mined. - let transactionReceipt = await this.getTransactionReceiptAsync(txHash); - if (!_.isNull(transactionReceipt) && !_.isNull(transactionReceipt.blockNumber)) { + let transactionReceipt = await this.getTransactionReceiptIfExistsAsync(txHash); + if (!_.isUndefined(transactionReceipt) && !_.isNull(transactionReceipt.blockNumber)) { const logsWithDecodedArgs = _.map( transactionReceipt.logs, this.abiDecoder.tryToDecodeLogOrNoop.bind(this.abiDecoder), @@ -600,8 +604,8 @@ export class Web3Wrapper { return reject(Web3WrapperErrors.TransactionMiningTimeout); } - transactionReceipt = await this.getTransactionReceiptAsync(txHash); - if (!_.isNull(transactionReceipt)) { + transactionReceipt = await this.getTransactionReceiptIfExistsAsync(txHash); + if (!_.isUndefined(transactionReceipt)) { intervalUtils.clearAsyncExcludingInterval(intervalId); const logsWithDecodedArgs = _.map( transactionReceipt.logs, diff --git a/packages/web3-wrapper/test/web3_wrapper_test.ts b/packages/web3-wrapper/test/web3_wrapper_test.ts index 164253777..935c67636 100644 --- a/packages/web3-wrapper/test/web3_wrapper_test.ts +++ b/packages/web3-wrapper/test/web3_wrapper_test.ts @@ -1,5 +1,5 @@ import * as chai from 'chai'; -import { BlockParamLiteral, JSONRPCErrorCallback, JSONRPCRequestPayload } from 'ethereum-types'; +import { BlockParamLiteral, JSONRPCErrorCallback, JSONRPCRequestPayload, TransactionReceipt } from 'ethereum-types'; import * as Ganache from 'ganache-core'; import * as _ from 'lodash'; import 'mocha'; @@ -98,6 +98,18 @@ describe('Web3Wrapper tests', () => { expect(typeof blockNumber).to.be.equal('number'); }); }); + describe('#getTransactionReceiptAsync/awaitTransactionSuccessAsync', () => { + it('get block number', async () => { + const payload = { from: addresses[0], to: addresses[1], value: 1 }; + const txHash = await web3Wrapper.sendTransactionAsync(payload); + await web3Wrapper.awaitTransactionSuccessAsync(txHash); + const receiptIfExists = await web3Wrapper.getTransactionReceiptIfExistsAsync(txHash); + expect(receiptIfExists).to.not.be.undefined(); + const receipt = receiptIfExists as TransactionReceipt; + expect(receipt.transactionIndex).to.be.a('number'); + expect(receipt.transactionHash).to.be.equal(txHash); + }); + }); describe('#getBlockIfExistsAsync', () => { it('gets block when supplied a valid BlockParamLiteral value', async () => { const blockParamLiteral = BlockParamLiteral.Earliest; -- cgit v1.2.3 From e1bc3f3f2d538c56ee2830260afced798096422d Mon Sep 17 00:00:00 2001 From: Leonid Logvinov Date: Tue, 20 Nov 2018 15:50:29 +0100 Subject: Add nonce to TxOpts --- packages/contract-wrappers/CHANGELOG.json | 10 +++++++ .../src/contract_wrappers/erc20_token_wrapper.ts | 3 ++ .../src/contract_wrappers/erc721_token_wrapper.ts | 3 ++ .../src/contract_wrappers/ether_token_wrapper.ts | 2 ++ .../src/contract_wrappers/exchange_wrapper.ts | 34 ++++++++++++++++++++++ .../src/contract_wrappers/forwarder_wrapper.ts | 4 +++ .../src/schemas/tx_opts_schema.ts | 1 + packages/contract-wrappers/src/types.ts | 2 ++ 8 files changed, 59 insertions(+) diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index fbf3972a9..b1568c9f3 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -1,4 +1,14 @@ [ + { + "version": "4.1.0", + "changes": [ + { + "note": + "Add a `nonce` field for `TxOpts` so that it's now possible to re-broadcast stuck transactions with higher gas cost", + "pr": 1292 + } + ] + }, { "timestamp": 1542208198, "version": "4.0.2", diff --git a/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts index 5e0ec1951..ad42cfd4f 100644 --- a/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/erc20_token_wrapper.ts @@ -111,6 +111,7 @@ export class ERC20TokenWrapper extends ContractWrapper { from: normalizedOwnerAddress, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, + nonce: txOpts.nonce, }), ); return txHash; @@ -281,6 +282,7 @@ export class ERC20TokenWrapper extends ContractWrapper { from: normalizedFromAddress, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, + nonce: txOpts.nonce, }), ); return txHash; @@ -342,6 +344,7 @@ export class ERC20TokenWrapper extends ContractWrapper { from: normalizedSenderAddress, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, + nonce: txOpts.nonce, }), ); return txHash; diff --git a/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts index 1610af47b..3bc7dc8e7 100644 --- a/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/erc721_token_wrapper.ts @@ -238,6 +238,7 @@ export class ERC721TokenWrapper extends ContractWrapper { gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, from: normalizedOwnerAddress, + nonce: txOpts.nonce, }), ); return txHash; @@ -298,6 +299,7 @@ export class ERC721TokenWrapper extends ContractWrapper { gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, from: tokenOwnerAddress, + nonce: txOpts.nonce, }), ); return txHash; @@ -369,6 +371,7 @@ export class ERC721TokenWrapper extends ContractWrapper { gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, from: normalizedSenderAddress, + nonce: txOpts.nonce, }), ); return txHash; diff --git a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts index 913c47cf7..6093f0f95 100644 --- a/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/ether_token_wrapper.ts @@ -71,6 +71,7 @@ export class EtherTokenWrapper extends ContractWrapper { value: amountInWei, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, + nonce: txOpts.nonce, }), ); return txHash; @@ -112,6 +113,7 @@ export class EtherTokenWrapper extends ContractWrapper { from: normalizedWithdrawerAddress, gas: txOpts.gasLimit, gasPrice: txOpts.gasPrice, + nonce: txOpts.nonce, }), ); return txHash; diff --git a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts index c76e51eee..c9556971a 100644 --- a/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/exchange_wrapper.ts @@ -196,6 +196,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } @@ -207,6 +208,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -243,6 +245,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); } @@ -254,6 +257,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -287,6 +291,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.fillOrKillOrder.sendTransactionAsync( @@ -297,6 +302,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -336,6 +342,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedSenderAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.executeTransaction.sendTransactionAsync( @@ -347,6 +354,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedSenderAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -382,6 +390,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.batchFillOrders.sendTransactionAsync( @@ -392,6 +401,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -425,6 +435,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.marketBuyOrders.sendTransactionAsync( @@ -435,6 +446,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -468,6 +480,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.marketSellOrders.sendTransactionAsync( @@ -478,6 +491,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -511,6 +525,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.marketBuyOrdersNoThrow.sendTransactionAsync( @@ -521,6 +536,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -554,6 +570,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.marketSellOrdersNoThrow.sendTransactionAsync( @@ -564,6 +581,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -599,6 +617,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.batchFillOrdersNoThrow.sendTransactionAsync( @@ -609,6 +628,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -644,6 +664,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.batchFillOrKillOrders.sendTransactionAsync( @@ -654,6 +675,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -682,12 +704,14 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedMakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.batchCancelOrders.sendTransactionAsync(orders, { from: normalizedMakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); return txHash; } @@ -735,6 +759,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); } @@ -747,6 +772,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -781,12 +807,14 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.preSign.sendTransactionAsync(hash, signerAddress, signature, { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); return txHash; } @@ -956,12 +984,14 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedMakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.cancelOrder.sendTransactionAsync(order, { from: normalizedMakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); return txHash; } @@ -992,6 +1022,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedSenderAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.setSignatureValidatorApproval.sendTransactionAsync( @@ -1001,6 +1032,7 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedSenderAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -1030,12 +1062,14 @@ export class ExchangeWrapper extends ContractWrapper { from: normalizedSenderAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); } const txHash = await exchangeInstance.cancelOrdersUpTo.sendTransactionAsync(targetOrderEpoch, { from: normalizedSenderAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }); return txHash; } diff --git a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts index 80742e030..5497f92b5 100644 --- a/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts +++ b/packages/contract-wrappers/src/contract_wrappers/forwarder_wrapper.ts @@ -124,6 +124,7 @@ export class ForwarderWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); } @@ -140,6 +141,7 @@ export class ForwarderWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; @@ -213,6 +215,7 @@ export class ForwarderWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); } @@ -230,6 +233,7 @@ export class ForwarderWrapper extends ContractWrapper { from: normalizedTakerAddress, gas: orderTransactionOpts.gasLimit, gasPrice: orderTransactionOpts.gasPrice, + nonce: orderTransactionOpts.nonce, }, ); return txHash; diff --git a/packages/contract-wrappers/src/schemas/tx_opts_schema.ts b/packages/contract-wrappers/src/schemas/tx_opts_schema.ts index 83c819be2..1c1588db7 100644 --- a/packages/contract-wrappers/src/schemas/tx_opts_schema.ts +++ b/packages/contract-wrappers/src/schemas/tx_opts_schema.ts @@ -3,6 +3,7 @@ export const txOptsSchema = { properties: { gasPrice: { $ref: '/numberSchema' }, gasLimit: { type: 'number' }, + nonce: { type: 'number' }, }, type: 'object', }; diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 5a5bdd530..21033cf3c 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -142,10 +142,12 @@ export interface MethodOpts { /** * gasPrice: Gas price in Wei to use for a transaction * gasLimit: The amount of gas to send with a transaction (in Gwei) + * nonce: The nonce to use for a transaction */ export interface TransactionOpts { gasPrice?: BigNumber; gasLimit?: number; + nonce?: number; } /** -- cgit v1.2.3 From 0c91bf1415a384ed18a630c89fe974f768040234 Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 20 Nov 2018 16:32:34 +0100 Subject: Update packages/contract-wrappers/CHANGELOG.json Co-Authored-By: LogvinovLeon --- packages/contract-wrappers/CHANGELOG.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contract-wrappers/CHANGELOG.json b/packages/contract-wrappers/CHANGELOG.json index b1568c9f3..1ea966fc6 100644 --- a/packages/contract-wrappers/CHANGELOG.json +++ b/packages/contract-wrappers/CHANGELOG.json @@ -4,7 +4,7 @@ "changes": [ { "note": - "Add a `nonce` field for `TxOpts` so that it's now possible to re-broadcast stuck transactions with higher gas cost", + "Add a `nonce` field for `TxOpts` so that it's now possible to re-broadcast stuck transactions with a higher gas amount", "pr": 1292 } ] -- cgit v1.2.3 From 7a38a196ad749699965f86e85e2a3caeada9a4bc Mon Sep 17 00:00:00 2001 From: Fabio B Date: Tue, 20 Nov 2018 16:42:49 +0100 Subject: Update packages/contract-wrappers/src/types.ts Co-Authored-By: LogvinovLeon --- packages/contract-wrappers/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/contract-wrappers/src/types.ts b/packages/contract-wrappers/src/types.ts index 21033cf3c..14d4649ae 100644 --- a/packages/contract-wrappers/src/types.ts +++ b/packages/contract-wrappers/src/types.ts @@ -142,7 +142,7 @@ export interface MethodOpts { /** * gasPrice: Gas price in Wei to use for a transaction * gasLimit: The amount of gas to send with a transaction (in Gwei) - * nonce: The nonce to use for a transaction + * nonce: The nonce to use for a transaction. If not specified, it defaults to the next incremented nonce. */ export interface TransactionOpts { gasPrice?: BigNumber; -- cgit v1.2.3