diff options
author | Steve Klebanoff <steve.klebanoff@gmail.com> | 2018-11-28 03:10:20 +0800 |
---|---|---|
committer | Steve Klebanoff <steve.klebanoff@gmail.com> | 2018-11-28 03:10:20 +0800 |
commit | 96a46bcb4b78744be08da9b957339802b8ba14fa (patch) | |
tree | a647bd1cf96e54489e444b9cb7e1bc0ad94362ba | |
parent | 5fd837cc4fbb8d70d3e72fe05fa5bf33a0331ab8 (diff) | |
parent | 4653e4c011410b67b0be0335aa1f44dfade86a2e (diff) | |
download | dexon-0x-contracts-96a46bcb4b78744be08da9b957339802b8ba14fa.tar.gz dexon-0x-contracts-96a46bcb4b78744be08da9b957339802b8ba14fa.tar.zst dexon-0x-contracts-96a46bcb4b78744be08da9b957339802b8ba14fa.zip |
Merge branch 'development' into feature/instant/dropdown-analytics
-rw-r--r-- | packages/instant/src/components/buy_button.tsx | 8 | ||||
-rw-r--r-- | packages/instant/src/components/payment_method_dropdown.tsx | 2 | ||||
-rw-r--r-- | packages/instant/src/components/zero_ex_instant_overlay.tsx | 9 | ||||
-rw-r--r-- | packages/instant/src/constants.ts | 2 | ||||
-rw-r--r-- | packages/instant/src/util/analytics.ts | 55 |
5 files changed, 73 insertions, 3 deletions
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 8b6121e43..eeb42d6fc 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -8,6 +8,7 @@ import { oc } from 'ts-optchain'; import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants'; import { ColorOption } from '../style/theme'; import { AffiliateInfo, ZeroExInstantError } from '../types'; +import { analytics } from '../util/analytics'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { util } from '../util/util'; @@ -59,6 +60,7 @@ export class BuyButton extends React.Component<BuyButtonProps> { // if we don't have a balance for the user, let the transaction through, it will be handled by the wallet const hasSufficientEth = _.isUndefined(accountEthBalanceInWei) || accountEthBalanceInWei.gte(ethNeededForBuy); if (!hasSufficientEth) { + analytics.trackBuyNotEnoughEth(buyQuote); this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH); return; } @@ -66,6 +68,7 @@ export class BuyButton extends React.Component<BuyButtonProps> { const gasInfo = await gasPriceEstimator.getGasInfoAsync(); const feeRecipient = oc(affiliateInfo).feeRecipient(); try { + analytics.trackBuyStarted(buyQuote); txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { feeRecipient, takerAddress: accountAddress, @@ -74,9 +77,11 @@ export class BuyButton extends React.Component<BuyButtonProps> { } catch (e) { if (e instanceof Error) { if (e.message === AssetBuyerError.SignatureRequestDenied) { + analytics.trackBuySignatureDenied(buyQuote); this.props.onSignatureDenied(buyQuote); return; } else if (e.message === AssetBuyerError.TransactionValueTooLow) { + analytics.trackBuySimulationFailed(buyQuote); this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow); return; } @@ -87,14 +92,17 @@ export class BuyButton extends React.Component<BuyButtonProps> { const expectedEndTimeUnix = startTimeUnix + gasInfo.estimatedTimeMs; this.props.onBuyProcessing(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); try { + analytics.trackBuyTxSubmitted(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); await web3Wrapper.awaitTransactionSuccessAsync(txHash); } catch (e) { if (e instanceof Error && e.message.startsWith(WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX)) { + analytics.trackBuyTxFailed(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); this.props.onBuyFailure(buyQuote, txHash); return; } throw e; } + analytics.trackBuyTxSucceeded(buyQuote, txHash, startTimeUnix, expectedEndTimeUnix); this.props.onBuySuccess(buyQuote, txHash); }; } diff --git a/packages/instant/src/components/payment_method_dropdown.tsx b/packages/instant/src/components/payment_method_dropdown.tsx index 7d7fecbc2..872ac0831 100644 --- a/packages/instant/src/components/payment_method_dropdown.tsx +++ b/packages/instant/src/components/payment_method_dropdown.tsx @@ -1,5 +1,5 @@ import { BigNumber } from '@0x/utils'; -import copy from 'copy-to-clipboard'; +import * as copy from 'copy-to-clipboard'; import * as React from 'react'; import { Network } from '../types'; diff --git a/packages/instant/src/components/zero_ex_instant_overlay.tsx b/packages/instant/src/components/zero_ex_instant_overlay.tsx index 2856ea3e3..b3fb57dd6 100644 --- a/packages/instant/src/components/zero_ex_instant_overlay.tsx +++ b/packages/instant/src/components/zero_ex_instant_overlay.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import { ZeroExInstantContainer } from '../components/zero_ex_instant_container'; +import { MAIN_CONTAINER_DIV_CLASS, OVERLAY_DIV_CLASS } from '../constants'; import { ColorOption } from '../style/theme'; import { Container } from './ui/container'; @@ -18,7 +19,7 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay const { onClose, zIndex, ...rest } = props; return ( <ZeroExInstantProvider {...rest}> - <Overlay zIndex={zIndex}> + <Overlay zIndex={zIndex} className={OVERLAY_DIV_CLASS}> <Flex height="100vh"> <Container position="absolute" top="0px" right="0px" display={{ default: 'initial', sm: 'none' }}> <Icon @@ -30,7 +31,11 @@ export const ZeroExInstantOverlay: React.StatelessComponent<ZeroExInstantOverlay padding="2em 2em" /> </Container> - <Container width={{ default: 'auto', sm: '100%' }} height={{ default: 'auto', sm: '100%' }}> + <Container + width={{ default: 'auto', sm: '100%' }} + height={{ default: 'auto', sm: '100%' }} + className={MAIN_CONTAINER_DIV_CLASS} + > <ZeroExInstantContainer /> </Container> </Flex> diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts index be6077ca9..163be40b3 100644 --- a/packages/instant/src/constants.ts +++ b/packages/instant/src/constants.ts @@ -7,6 +7,8 @@ export const ETH_DECIMALS = 18; export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer'; export const INJECTED_DIV_CLASS = 'zeroExInstantResetRoot'; export const INJECTED_DIV_ID = 'zeroExInstant'; +export const OVERLAY_DIV_CLASS = 'zeroExInstantOverlay'; +export const MAIN_CONTAINER_DIV_CLASS = 'zeroExInstantMainContainer'; export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed'; export const GWEI_IN_WEI = new BigNumber(1000000000); export const ONE_SECOND_MS = 1000; diff --git a/packages/instant/src/util/analytics.ts b/packages/instant/src/util/analytics.ts index 05988965b..5bc9bb385 100644 --- a/packages/instant/src/util/analytics.ts +++ b/packages/instant/src/util/analytics.ts @@ -1,3 +1,6 @@ +import { BuyQuote } from '@0x/asset-buyer'; +import * as _ from 'lodash'; + import { AffiliateInfo, Asset, Network, OrderSource, ProviderState } from '../types'; import { EventProperties, heapUtil } from './heap'; @@ -23,6 +26,13 @@ enum EventNames { PAYMENT_METHOD_DROPDOWN_OPENED = 'Payment Method - Dropdown Opened', PAYMENT_METHOD_OPENED_ETHERSCAN = 'Payment Method - Opened Etherscan', PAYMENT_METHOD_COPIED_ADDRESS = 'Payment Method - Copied Address', + BUY_NOT_ENOUGH_ETH = 'Buy - Not Enough Eth', + BUY_STARTED = 'Buy - Started', + BUY_SIGNATURE_DENIED = 'Buy - Signature Denied', + BUY_SIMULATION_FAILED = 'Buy - Simulation Failed', + BUY_TX_SUBMITTED = 'Buy - Tx Submitted', + BUY_TX_SUCCEEDED = 'Buy - Tx Succeeded', + BUY_TX_FAILED = 'Buy - Tx Failed', TOKEN_SELECTOR_OPENED = 'Token Selector - Opened', TOKEN_SELECTOR_CLOSED = 'Token Selector - Closed', TOKEN_SELECTOR_CHOSE = 'Token Selector - Chose', @@ -46,6 +56,23 @@ function trackingEventFnWithPayload(eventName: EventNames): (eventProperties: Ev }; } +const buyQuoteEventProperties = (buyQuote: BuyQuote) => { + const assetBuyAmount = buyQuote.assetBuyAmount.toString(); + const assetEthAmount = buyQuote.worstCaseQuoteInfo.assetEthAmount.toString(); + const feeEthAmount = buyQuote.worstCaseQuoteInfo.feeEthAmount.toString(); + const totalEthAmount = buyQuote.worstCaseQuoteInfo.totalEthAmount.toString(); + const feePercentage = !_.isUndefined(buyQuote.feePercentage) ? buyQuote.feePercentage.toString() : 0; + const hasFeeOrders = !_.isEmpty(buyQuote.feeOrders) ? 'true' : 'false'; + return { + assetBuyAmount, + assetEthAmount, + feeEthAmount, + totalEthAmount, + feePercentage, + hasFeeOrders, + }; +}; + export interface AnalyticsUserOptions { lastKnownEthAddress?: string; ethBalanceInUnitAmount?: string; @@ -115,6 +142,34 @@ export const analytics = { trackPaymentMethodDropdownOpened: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_DROPDOWN_OPENED), trackPaymentMethodOpenedEtherscan: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_OPENED_ETHERSCAN), trackPaymentMethodCopiedAddress: trackingEventFnWithoutPayload(EventNames.PAYMENT_METHOD_COPIED_ADDRESS), + trackBuyNotEnoughEth: (buyQuote: BuyQuote) => + trackingEventFnWithPayload(EventNames.BUY_NOT_ENOUGH_ETH)(buyQuoteEventProperties(buyQuote)), + trackBuyStarted: (buyQuote: BuyQuote) => + trackingEventFnWithPayload(EventNames.BUY_STARTED)(buyQuoteEventProperties(buyQuote)), + trackBuySignatureDenied: (buyQuote: BuyQuote) => + trackingEventFnWithPayload(EventNames.BUY_SIGNATURE_DENIED)(buyQuoteEventProperties(buyQuote)), + trackBuySimulationFailed: (buyQuote: BuyQuote) => + trackingEventFnWithPayload(EventNames.BUY_SIMULATION_FAILED)(buyQuoteEventProperties(buyQuote)), + trackBuyTxSubmitted: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + trackingEventFnWithPayload(EventNames.BUY_TX_SUBMITTED)({ + ...buyQuoteEventProperties(buyQuote), + txHash, + expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix, + }), + trackBuyTxSucceeded: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + trackingEventFnWithPayload(EventNames.BUY_TX_SUCCEEDED)({ + ...buyQuoteEventProperties(buyQuote), + txHash, + expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix, + actualTxTimeMs: new Date().getTime() - startTimeUnix, + }), + trackBuyTxFailed: (buyQuote: BuyQuote, txHash: string, startTimeUnix: number, expectedEndTimeUnix: number) => + trackingEventFnWithPayload(EventNames.BUY_TX_FAILED)({ + ...buyQuoteEventProperties(buyQuote), + txHash, + expectedTxTimeMs: expectedEndTimeUnix - startTimeUnix, + actualTxTimeMs: new Date().getTime() - startTimeUnix, + }), trackTokenSelectorOpened: trackingEventFnWithoutPayload(EventNames.TOKEN_SELECTOR_OPENED), trackTokenSelectorClosed: (closedVia: TokenSelectorClosedVia) => trackingEventFnWithPayload(EventNames.TOKEN_SELECTOR_CLOSED)({ closedVia }), |