aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant
diff options
context:
space:
mode:
authorSteve Klebanoff <steve.klebanoff@gmail.com>2018-11-21 05:26:00 +0800
committerSteve Klebanoff <steve.klebanoff@gmail.com>2018-11-21 05:26:00 +0800
commiteca63b1a5815c61901453837f9c2b737fa82eb20 (patch)
tree7763d95f1922f6c16848a8b506384e6e9992260b /packages/instant
parent2bda6dd719d748a4bfa5ff8e23e97924e0258af1 (diff)
parentba41fc9275bebe17577f87d72f54b7e7dc420acc (diff)
downloaddexon-sol-tools-eca63b1a5815c61901453837f9c2b737fa82eb20.tar
dexon-sol-tools-eca63b1a5815c61901453837f9c2b737fa82eb20.tar.gz
dexon-sol-tools-eca63b1a5815c61901453837f9c2b737fa82eb20.tar.bz2
dexon-sol-tools-eca63b1a5815c61901453837f9c2b737fa82eb20.tar.lz
dexon-sol-tools-eca63b1a5815c61901453837f9c2b737fa82eb20.tar.xz
dexon-sol-tools-eca63b1a5815c61901453837f9c2b737fa82eb20.tar.zst
dexon-sol-tools-eca63b1a5815c61901453837f9c2b737fa82eb20.zip
Merge branch 'development' into feature/header-tweaks
Diffstat (limited to 'packages/instant')
-rw-r--r--packages/instant/src/assets/powered_by_0x.svg27
-rw-r--r--packages/instant/src/components/zero_ex_instant_container.tsx13
-rw-r--r--packages/instant/src/components/zero_ex_instant_provider.tsx14
-rw-r--r--packages/instant/src/constants.ts3
-rw-r--r--packages/instant/src/globals.d.ts6
-rw-r--r--packages/instant/src/index.umd.ts3
-rw-r--r--packages/instant/src/redux/analytics_middleware.ts59
-rw-r--r--packages/instant/src/redux/store.ts7
-rw-r--r--packages/instant/src/types.ts1
-rw-r--r--packages/instant/src/util/analytics.ts64
-rw-r--r--packages/instant/src/util/heap.ts113
-rw-r--r--packages/instant/src/util/provider_state_factory.ts2
-rw-r--r--packages/instant/webpack.config.js115
13 files changed, 383 insertions, 44 deletions
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 @@
+<svg width="114" height="20" viewBox="0 0 114 20" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M1.17959 11.0032V14.5455H0V5.49716H3.29917C4.27807 5.49716 5.04398 5.74988 5.59692 6.25533C6.15395 6.76077 6.43246 7.42986 6.43246 8.26261C6.43246 9.14092 6.16009 9.8183 5.61535 10.2947C5.0747 10.767 4.29855 11.0032 3.28688 11.0032H1.17959ZM1.17959 10.0275H3.29917C3.92992 10.0275 4.41323 9.87837 4.74909 9.58008C5.08494 9.27764 5.25287 8.84263 5.25287 8.27504C5.25287 7.73645 5.08494 7.30558 4.74909 6.98242C4.41323 6.65927 3.95245 6.49148 3.36675 6.47905H1.17959V10.0275Z" fill="#777777"/>
+<path d="M7.37245 11.1213C7.37245 10.4625 7.49942 9.87009 7.75336 9.34393C8.01139 8.81777 8.36773 8.41175 8.82236 8.12589C9.28109 7.84002 9.80331 7.69709 10.389 7.69709C11.2942 7.69709 12.0253 8.01403 12.5823 8.6479C13.1434 9.28178 13.424 10.1249 13.424 11.1772V11.258C13.424 11.9126 13.2991 12.5009 13.0492 13.0229C12.8035 13.5408 12.4492 13.9447 11.9864 14.2347C11.5276 14.5247 10.9993 14.6697 10.4013 14.6697C9.50022 14.6697 8.76912 14.3528 8.20799 13.7189C7.65096 13.085 7.37245 12.2461 7.37245 11.2021V11.1213ZM8.51518 11.258C8.51518 12.0037 8.68515 12.6024 9.02511 13.054C9.36915 13.5056 9.82788 13.7314 10.4013 13.7314C10.9788 13.7314 11.4375 13.5035 11.7775 13.0478C12.1174 12.5879 12.2874 11.9457 12.2874 11.1213C12.2874 10.3838 12.1133 9.78723 11.7652 9.3315C11.4212 8.87163 10.9624 8.64169 10.389 8.64169C9.82788 8.64169 9.3753 8.86748 9.03125 9.31907C8.6872 9.77066 8.51518 10.417 8.51518 11.258Z" fill="#777777"/>
+<path d="M20.735 12.9608L22.0129 7.82138H23.1495L21.2142 14.5455H20.2927L18.6769 9.44957L17.1041 14.5455H16.1825L14.2534 7.82138H15.3838L16.6925 12.8551L18.2407 7.82138H19.1561L20.735 12.9608Z" fill="#777777"/>
+<path d="M27.0692 14.6697C26.1681 14.6697 25.4349 14.3714 24.8697 13.7749C24.3045 13.1741 24.0219 12.3725 24.0219 11.3699V11.1586C24.0219 10.4915 24.1468 9.89702 24.3967 9.375C24.6506 8.84884 25.0028 8.43868 25.4534 8.14453C25.908 7.84624 26.3995 7.69709 26.9279 7.69709C27.7921 7.69709 28.4638 7.98503 28.943 8.5609C29.4222 9.13678 29.6618 9.96123 29.6618 11.0343V11.5128H25.1585C25.1749 12.1757 25.3653 12.7122 25.7298 13.1223C26.0985 13.5283 26.5654 13.7314 27.1306 13.7314C27.532 13.7314 27.872 13.6485 28.1505 13.4828C28.429 13.3171 28.6727 13.0975 28.8816 12.824L29.5758 13.3709C29.0188 14.2368 28.1832 14.6697 27.0692 14.6697ZM26.9279 8.64169C26.4691 8.64169 26.0841 8.81155 25.7729 9.15128C25.4616 9.48686 25.2691 9.95916 25.1953 10.5682H28.5252V10.4812C28.4925 9.89702 28.3368 9.44543 28.0583 9.12642C27.7798 8.80327 27.403 8.64169 26.9279 8.64169Z" fill="#777777"/>
+<path d="M34.1959 8.85298C34.0238 8.82398 33.8375 8.80948 33.6368 8.80948C32.8914 8.80948 32.3855 9.13056 32.1193 9.77273V14.5455H30.9827V7.82138H32.0886L32.107 8.59819C32.4797 7.99746 33.0081 7.69709 33.6921 7.69709C33.9133 7.69709 34.0812 7.72609 34.1959 7.78409V8.85298Z" fill="#777777"/>
+<path d="M37.8821 14.6697C36.981 14.6697 36.2479 14.3714 35.6826 13.7749C35.1174 13.1741 34.8348 12.3725 34.8348 11.3699V11.1586C34.8348 10.4915 34.9597 9.89702 35.2096 9.375C35.4635 8.84884 35.8158 8.43868 36.2663 8.14453C36.7209 7.84624 37.2124 7.69709 37.7408 7.69709C38.605 7.69709 39.2767 7.98503 39.7559 8.5609C40.2351 9.13678 40.4747 9.96123 40.4747 11.0343V11.5128H35.9714C35.9878 12.1757 36.1782 12.7122 36.5428 13.1223C36.9114 13.5283 37.3783 13.7314 37.9435 13.7314C38.3449 13.7314 38.6849 13.6485 38.9634 13.4828C39.2419 13.3171 39.4856 13.0975 39.6945 12.824L40.3887 13.3709C39.8317 14.2368 38.9962 14.6697 37.8821 14.6697ZM37.7408 8.64169C37.2821 8.64169 36.8971 8.81155 36.5858 9.15128C36.2745 9.48686 36.082 9.95916 36.0083 10.5682H39.3382V10.4812C39.3054 9.89702 39.1497 9.44543 38.8712 9.12642C38.5927 8.80327 38.2159 8.64169 37.7408 8.64169Z" fill="#777777"/>
+<path d="M41.5192 11.1275C41.5192 10.0959 41.7608 9.26728 42.2441 8.64169C42.7274 8.01196 43.3602 7.69709 44.1425 7.69709C44.9207 7.69709 45.5372 7.96638 45.9918 8.50497V5H47.1284V14.5455H46.0839L46.0287 13.8246C45.574 14.388 44.9412 14.6697 44.1302 14.6697C43.3602 14.6697 42.7315 14.3507 42.2441 13.7127C41.7608 13.0747 41.5192 12.242 41.5192 11.2145V11.1275ZM42.6558 11.258C42.6558 12.0203 42.8114 12.6169 43.1227 13.0478C43.434 13.4786 43.864 13.6941 44.4129 13.6941C45.1337 13.6941 45.66 13.3668 45.9918 12.7122V9.62358C45.6518 8.9897 45.1296 8.67276 44.4251 8.67276C43.8681 8.67276 43.434 8.89027 43.1227 9.32528C42.8114 9.7603 42.6558 10.4045 42.6558 11.258Z" fill="#777777"/>
+<path d="M57.6464 11.258C57.6464 12.2855 57.4129 13.112 56.946 13.7376C56.4791 14.359 55.8524 14.6697 55.066 14.6697C54.2264 14.6697 53.5772 14.3694 53.1185 13.7686L53.0632 14.5455H52.0188V5H53.1553V8.5609C53.6141 7.98503 54.2469 7.69709 55.0538 7.69709C55.8606 7.69709 56.4934 8.00574 56.9522 8.62305C57.415 9.24035 57.6464 10.0855 57.6464 11.1586V11.258ZM56.5098 11.1275C56.5098 10.3445 56.3603 9.73958 56.0613 9.31285C55.7623 8.88613 55.3323 8.67276 54.7711 8.67276C54.0216 8.67276 53.483 9.02492 53.1553 9.72923V12.6376C53.5035 13.3419 54.0462 13.6941 54.7834 13.6941C55.3282 13.6941 55.7521 13.4807 56.0552 13.054C56.3583 12.6272 56.5098 11.9851 56.5098 11.1275Z" fill="#777777"/>
+<path d="M61.1852 12.8613L62.7334 7.82138H63.9498L61.2773 15.5833C60.8637 16.7019 60.2063 17.2612 59.3052 17.2612L59.0902 17.2425L58.6663 17.1618V16.2296L58.9734 16.2544C59.3584 16.2544 59.6574 16.1757 59.8704 16.0183C60.0875 15.8609 60.2657 15.5729 60.4049 15.1545L60.6568 14.4709L58.2853 7.82138H59.5264L61.1852 12.8613Z" fill="#777777"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M102.319 9.94708L98.7681 12.2635C98.8595 13.5364 99.4513 14.1727 100.544 14.1727C101.727 14.1727 102.319 13.414 102.319 11.8964V9.94708ZM98.7527 11.0088L102.304 8.69233C102.263 8.02927 102.097 7.53857 101.805 7.22035C101.513 6.90224 101.087 6.74304 100.528 6.74304C99.9338 6.74304 99.4892 6.92776 99.1947 7.29714C98.8999 7.66658 98.7527 8.23403 98.7527 8.99935V11.0088ZM104.149 11.6161C104.149 12.2437 104.066 12.7967 103.901 13.275C103.736 13.7535 103.498 14.154 103.188 14.4766C102.879 14.7993 102.5 15.043 102.053 15.2076C101.606 15.3722 101.103 15.4546 100.544 15.4546C99.9902 15.4546 99.4897 15.3722 99.0427 15.2076C98.5956 15.043 98.2158 14.7993 97.9034 14.4766C97.591 14.154 97.3496 13.7535 97.1794 13.275C97.0091 12.7967 96.9241 12.2437 96.9241 11.6161V9.293C96.9241 8.66551 97.0079 8.11262 97.1756 7.63416C97.3433 7.15582 97.5833 6.75525 97.8958 6.43253C98.2083 6.10992 98.5866 5.8663 99.0313 5.70156C99.4758 5.53699 99.975 5.45459 100.529 5.45459C101.088 5.45459 101.591 5.53699 102.038 5.70156C102.485 5.8663 102.865 6.10992 103.177 6.43253C103.489 6.75525 103.73 7.15582 103.897 7.63416C104.065 8.11262 104.149 8.66551 104.149 9.293V11.6161Z" fill="#777777"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M110.041 10.4915L111.947 7.95448H113.911L111.09 11.6491L114 15.4545H112.043L110.063 12.8274L108.091 15.4545H106.119L109.029 11.6491L106.207 7.95448H108.165L110.041 10.4915Z" fill="#777777"/>
+<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="76" y="13" width="13" height="7">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M76.666 20H88.9359V13.425H76.666V20Z" fill="white"/>
+</mask>
+<g mask="url(#mask0)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M76.666 18.644C77.9189 19.3997 79.3537 19.8757 80.8969 19.9789C83.0284 20.1214 85.0448 19.534 86.7198 18.4267C87.5526 17.8761 88.3005 17.1969 88.9359 16.4141C88.4089 15.6562 87.8483 14.8742 87.2561 14.0775L86.7722 13.425C86.1355 14.4641 85.2199 15.2969 84.1423 15.8178L82.4893 14.1447L76.666 18.644Z" fill="#777777"/>
+</g>
+<mask id="mask1" mask-type="alpha" maskUnits="userSpaceOnUse" x="71" y="5" width="8" height="13">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M71.7593 5.17493V17.8053H78.1152V5.17493L71.7593 5.17493Z" fill="white"/>
+</mask>
+<g mask="url(#mask1)">
+<path fill-rule="evenodd" clip-rule="evenodd" d="M73.0424 5.17493C72.3281 6.45818 71.8782 7.92349 71.7797 9.49804C71.6417 11.7039 72.211 13.7904 73.2841 15.523C73.815 16.3803 74.4695 17.1504 75.2234 17.8053C75.9567 17.2604 76.7136 16.6807 77.4848 16.0686L78.1153 15.5695C77.1119 14.9113 76.3077 13.9658 75.8044 12.853L77.4333 11.1274L73.0424 5.17493Z" fill="#777777"/>
+</g>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M86.4377 1.38342C85.1877 0.612615 83.756 0.126653 82.2157 0.0214596C80.0888 -0.123789 78.0769 0.475348 76.4064 1.60452C75.5797 2.16325 74.8373 2.85192 74.2058 3.64528C74.7312 4.41698 75.2901 5.21342 75.8803 6.02502L76.3615 6.68845C76.9964 5.63221 77.9085 4.78555 78.982 4.25602L78.9832 4.25547L80.5359 5.8528L86.4377 1.38342Z" fill="#777777"/>
+<path fill-rule="evenodd" clip-rule="evenodd" d="M90.0676 14.9203C90.769 13.6715 91.2122 12.2498 91.3097 10.722C91.4476 8.56117 90.8794 6.51701 89.8081 4.81903C89.2755 3.97475 88.6185 3.21662 87.8611 2.57239C87.128 3.10659 86.3715 3.67498 85.6007 4.27538L84.9695 4.76579C85.9764 5.41241 86.7834 6.3426 87.2872 7.43761L87.2969 7.46039L85.7288 9.10965L90.0676 14.9203Z" fill="#777777"/>
+</svg>
diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx
index 698bfef17..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,7 @@
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';
import { CurrentStandardSlidingPanel } from '../containers/current_standard_sliding_panel';
@@ -64,6 +66,17 @@ export class ZeroExInstantContainer extends React.Component<{}, ZeroExInstantCon
</SlidingPanel>
<CurrentStandardSlidingPanel />
</Container>
+ <Container
+ display={{ sm: 'none', default: 'block' }}
+ marginTop="10px"
+ marginLeft="auto"
+ marginRight="auto"
+ width="140px"
+ >
+ <a href={ZERO_EX_SITE_URL} target="_blank">
+ <PoweredByLogo />
+ </a>
+ </Container>
</Container>
</React.Fragment>
);
diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx
index 8be53ee20..9435d8c7c 100644
--- a/packages/instant/src/components/zero_ex_instant_provider.tsx
+++ b/packages/instant/src/components/zero_ex_instant_provider.tsx
@@ -12,6 +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, disableAnalytics } from '../util/analytics';
import { assetUtils } from '../util/asset';
import { errorFlasher } from '../util/error_flasher';
import { gasPriceEstimator } from '../util/gas_price_estimator';
@@ -36,6 +37,7 @@ export interface ZeroExInstantProviderOptionalProps {
additionalAssetMetaDataMap: ObjectMap<AssetMetaData>;
networkId: Network;
affiliateInfo: AffiliateInfo;
+ shouldDisableAnalyticsTracking: boolean;
}
export class ZeroExInstantProvider extends React.Component<ZeroExInstantProviderProps> {
@@ -121,6 +123,18 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider
gasPriceEstimator.getGasInfoAsync();
// tslint:disable-next-line:no-floating-promises
this._flashErrorIfWrongNetwork();
+
+ // Analytics
+ disableAnalytics(this.props.shouldDisableAnalyticsTracking || false);
+ analytics.addEventProperties({
+ embeddedHost: window.location.host,
+ embeddedUrl: window.location.href,
+ networkId: state.network,
+ providerName: state.providerState.name,
+ gitSha: process.env.GIT_SHA,
+ npmVersion: process.env.NPM_PACKAGE_VERSION,
+ });
+ analytics.trackInstantOpened();
}
public componentWillUnmount(): void {
if (this._accountUpdateHeartbeat) {
diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts
index 5bd2349b3..be6077ca9 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_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;
@@ -31,6 +32,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,
@@ -47,4 +49,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/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 */
diff --git a/packages/instant/src/index.umd.ts b/packages/instant/src/index.umd.ts
index 0274db30c..5010347b3 100644
--- a/packages/instant/src/index.umd.ts
+++ b/packages/instant/src/index.umd.ts
@@ -35,6 +35,9 @@ export const render = (props: ZeroExInstantOverlayProps, selector: string = DEFA
if (!_.isUndefined(props.provider)) {
assert.isWeb3Provider('props.provider', props.provider);
}
+ if (!_.isUndefined(props.shouldDisableAnalyticsTracking)) {
+ assert.isBoolean('props.shouldDisableAnalyticsTracking', props.shouldDisableAnalyticsTracking);
+ }
assert.isString('selector', selector);
const appendToIfExists = document.querySelector(selector);
assert.assert(!_.isNull(appendToIfExists), `Could not find div with selector: ${selector}`);
diff --git a/packages/instant/src/redux/analytics_middleware.ts b/packages/instant/src/redux/analytics_middleware.ts
new file mode 100644
index 000000000..f971dbd33
--- /dev/null
+++ b/packages/instant/src/redux/analytics_middleware.ts
@@ -0,0 +1,59 @@
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as _ from 'lodash';
+import { Middleware } from 'redux';
+
+import { ETH_DECIMALS } from '../constants';
+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 didJustTurnReady = curAccount.state === AccountState.Ready && prevAccount.state !== AccountState.Ready;
+ if (didJustTurnReady) {
+ 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;
+
+ const nextAction = next(middlewareAction) as Action;
+
+ 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 && shouldTriggerWalletReady(prevAccount, curAccount)) {
+ const ethAddress = curAccount.address;
+ analytics.addUserProperties({ ethAddress });
+ analytics.trackWalletReady();
+ }
+ break;
+ case ActionTypes.UPDATE_ACCOUNT_ETH_BALANCE:
+ if (
+ curAccount.state === AccountState.Ready &&
+ curAccount.ethBalanceInWei &&
+ !_.isEqual(curAccount, prevAccount)
+ ) {
+ const ethBalanceInUnitAmount = Web3Wrapper.toUnitAmount(
+ curAccount.ethBalanceInWei,
+ ETH_DECIMALS,
+ ).toString();
+ analytics.addUserProperties({ ethBalanceInUnitAmount });
+ }
+ }
+
+ return nextAction;
+};
diff --git a/packages/instant/src/redux/store.ts b/packages/instant/src/redux/store.ts
index 20710765d..11bba3876 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 } from 'redux-devtools-extension/developmentOnly';
+import { analyticsMiddleware } from './analytics_middleware';
import { createReducer, State } from './reducer';
export type Store = ReduxStore<State>;
@@ -9,6 +10,6 @@ export type Store = ReduxStore<State>;
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/types.ts b/packages/instant/src/types.ts
index 2d4a8a850..999d50fed 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -165,4 +165,5 @@ export enum ProviderType {
Mist = 'MIST',
CoinbaseWallet = 'COINBASE_WALLET',
Cipher = 'CIPHER',
+ Fallback = 'FALLBACK',
}
diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts
new file mode 100644
index 000000000..2ffaac1dd
--- /dev/null
+++ b/packages/instant/src/util/analytics.ts
@@ -0,0 +1,64 @@
+import { ObjectMap } from '@0x/types';
+
+import { heapUtil } from './heap';
+
+let isDisabled = false;
+export const disableAnalytics = (shouldDisableAnalytics: boolean) => {
+ isDisabled = shouldDisableAnalytics;
+};
+export const evaluateIfEnabled = (fnCall: () => void) => {
+ if (isDisabled) {
+ return;
+ }
+ fnCall();
+};
+
+enum EventNames {
+ INSTANT_OPENED = 'Instant - Opened',
+ WALLET_READY = 'Wallet - Ready',
+}
+const track = (eventName: EventNames, eventData: ObjectMap<string | number> = {}): void => {
+ evaluateIfEnabled(() => {
+ heapUtil.evaluateHeapCall(heap => heap.track(eventName, eventData));
+ });
+};
+function trackingEventFnWithoutPayload(eventName: EventNames): () => void {
+ return () => {
+ track(eventName);
+ };
+}
+// tslint:disable-next-line:no-unused-variable
+function trackingEventFnWithPayload<T extends ObjectMap<string | number>>(
+ eventName: EventNames,
+): (eventDataProperties: T) => void {
+ return (eventDataProperties: T) => {
+ track(eventName, eventDataProperties);
+ };
+}
+
+export interface AnalyticsUserOptions {
+ ethAddress?: string;
+ ethBalanceInUnitAmount?: string;
+}
+export interface AnalyticsEventOptions {
+ embeddedHost?: string;
+ embeddedUrl?: string;
+ networkId?: number;
+ providerName?: string;
+ gitSha?: string;
+ npmVersion?: string;
+}
+export const analytics = {
+ addUserProperties: (properties: AnalyticsUserOptions): void => {
+ evaluateIfEnabled(() => {
+ heapUtil.evaluateHeapCall(heap => heap.addUserProperties(properties));
+ });
+ },
+ addEventProperties: (properties: AnalyticsEventOptions): void => {
+ evaluateIfEnabled(() => {
+ heapUtil.evaluateHeapCall(heap => heap.addEventProperties(properties));
+ });
+ },
+ trackWalletReady: trackingEventFnWithoutPayload(EventNames.WALLET_READY),
+ trackInstantOpened: trackingEventFnWithoutPayload(EventNames.INSTANT_OPENED),
+};
diff --git a/packages/instant/src/util/heap.ts b/packages/instant/src/util/heap.ts
new file mode 100644
index 000000000..78ec3b3cc
--- /dev/null
+++ b/packages/instant/src/util/heap.ts
@@ -0,0 +1,113 @@
+import { ObjectMap } from '@0x/types';
+import { logUtils } from '@0x/utils';
+import * as _ from 'lodash';
+
+import { HEAP_ANALYTICS_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<string | number>): void;
+ resetIdentity(): void;
+ addUserProperties(properties: AnalyticsUserOptions): void;
+ addEventProperties(properties: AnalyticsEventOptions): void;
+ removeEventProperty(property: string): void;
+ clearEventProperties(): void;
+}
+interface ModifiedWindow {
+ heap?: HeapAnalytics;
+ zeroExInstantLoadedHeap?: boolean;
+}
+const getWindow = (): ModifiedWindow => {
+ return window as ModifiedWindow;
+};
+
+const setupZeroExInstantHeap = () => {
+ if (_.isUndefined(HEAP_ANALYTICS_ID)) {
+ return;
+ }
+
+ 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) {
+ ((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]);
+ });
+ (window as any).heap.load(HEAP_ANALYTICS_ID);
+ /* tslint:enable */
+
+ return curWindow.heap as HeapAnalytics;
+};
+
+export const heapUtil = {
+ getHeap: (): HeapAnalytics | undefined => {
+ const curWindow = getWindow();
+ const hasOtherExistingHeapIntegration = curWindow.heap && !curWindow.zeroExInstantLoadedHeap;
+ if (hasOtherExistingHeapIntegration) {
+ return undefined;
+ }
+
+ const zeroExInstantHeapIntegration = curWindow.zeroExInstantLoadedHeap && curWindow.heap;
+ if (zeroExInstantHeapIntegration) {
+ return zeroExInstantHeapIntegration;
+ }
+
+ return setupZeroExInstantHeap();
+ },
+ evaluateHeapCall: (heapFunctionCall: (heap: HeapAnalytics) => void): void => {
+ if (_.isUndefined(HEAP_ANALYTICS_ID)) {
+ return;
+ }
+
+ const curHeap = heapUtil.getHeap();
+ if (curHeap) {
+ try {
+ if (curHeap.appid !== HEAP_ANALYTICS_ID) {
+ // 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
+ // TODO(sk): error reporter here
+ logUtils.log('Analytics error', e);
+ }
+ }
+ },
+};
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),
diff --git a/packages/instant/webpack.config.js b/packages/instant/webpack.config.js
index fae303712..41276809c 100644
--- a/packages/instant/webpack.config.js
+++ b/packages/instant/webpack.config.js
@@ -1,46 +1,81 @@
-const path = require('path');
+const childProcess = require('child_process');
const ip = require('ip');
+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 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',
- },
- devtool: 'source-map',
- resolve: {
- extensions: ['.js', '.json', '.ts', '.tsx'],
- },
- module: {
- rules: [
- {
- test: /\.(ts|tsx)$/,
- loader: 'awesome-typescript-loader',
- },
- {
- test: /\.svg$/,
- loader: 'svg-react-loader',
- },
+
+const GIT_SHA = childProcess
+ .execSync('git rev-parse HEAD')
+ .toString()
+ .trim();
+
+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') {
+ return process.env[HEAP_PRODUCTION_ENV_VAR_NAME];
+ }
+
+ 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',
+ },
+ {
+ test: /\.svg$/,
+ loader: 'svg-react-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;