From 86fd211ba6f5b15c660f02bc84b335b328c388c8 Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Tue, 26 Jul 2022 15:54:39 -0400 Subject: [PATCH 1/8] init commit --- src/components/AmplitudeAnalytics/utils.ts | 6 ++++- src/components/swap/ConfirmSwapModal.tsx | 5 ++++- src/components/swap/SwapDetailsDropdown.tsx | 25 ++++++++++++++++----- src/components/swap/SwapModalFooter.tsx | 13 +++++++++-- src/pages/Swap/index.tsx | 3 +++ 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/components/AmplitudeAnalytics/utils.ts b/src/components/AmplitudeAnalytics/utils.ts index f72136f16b5..eec5822723b 100644 --- a/src/components/AmplitudeAnalytics/utils.ts +++ b/src/components/AmplitudeAnalytics/utils.ts @@ -1,10 +1,14 @@ import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' -export const getDurationTillTimestampSinceEpoch = (futureTimestampSinceEpoch?: number): number | undefined => { +export const getDurationTillTimestampSinceEpochSeconds = (futureTimestampSinceEpoch?: number): number | undefined => { if (!futureTimestampSinceEpoch) return undefined return futureTimestampSinceEpoch - new Date().getTime() / 1000 } +export const getDurationFromDateTillNowMilliseconds = (date: Date): number => { + return Math.abs(new Date().getUTCMilliseconds() - date.getUTCMilliseconds()) +} + export const getNumberFormattedToDecimalPlace = ( intialNumberObject: Percent | CurrencyAmount, decimalPlace: number diff --git a/src/components/swap/ConfirmSwapModal.tsx b/src/components/swap/ConfirmSwapModal.tsx index edd95788520..4775ffd165e 100644 --- a/src/components/swap/ConfirmSwapModal.tsx +++ b/src/components/swap/ConfirmSwapModal.tsx @@ -26,6 +26,7 @@ export default function ConfirmSwapModal({ isOpen, attemptingTxn, txHash, + swapQuoteReceivedDate, }: { isOpen: boolean trade: InterfaceTrade | undefined @@ -38,6 +39,7 @@ export default function ConfirmSwapModal({ onConfirm: () => void swapErrorMessage: ReactNode | undefined onDismiss: () => void + swapQuoteReceivedDate: Date | undefined }) { const showAcceptChanges = useMemo( () => Boolean(trade && originalTrade && tradeMeaningfullyDiffers(trade, originalTrade)), @@ -65,9 +67,10 @@ export default function ConfirmSwapModal({ allowedSlippage={allowedSlippage} disabledConfirm={showAcceptChanges} swapErrorMessage={swapErrorMessage} + swapQuoteReceivedDate={swapQuoteReceivedDate} /> ) : null - }, [onConfirm, showAcceptChanges, swapErrorMessage, trade, allowedSlippage, txHash]) + }, [onConfirm, showAcceptChanges, swapErrorMessage, trade, allowedSlippage, txHash, swapQuoteReceivedDate]) // text to show while loading const pendingText = ( diff --git a/src/components/swap/SwapDetailsDropdown.tsx b/src/components/swap/SwapDetailsDropdown.tsx index 9c9bbecb010..5e5a0119547 100644 --- a/src/components/swap/SwapDetailsDropdown.tsx +++ b/src/components/swap/SwapDetailsDropdown.tsx @@ -4,7 +4,11 @@ import { useWeb3React } from '@web3-react/core' import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants' import { Trace } from 'components/AmplitudeAnalytics/Trace' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' -import { formatPercentInBasisPointsNumber, getNumberFormattedToDecimalPlace } from 'components/AmplitudeAnalytics/utils' +import { + formatPercentInBasisPointsNumber, + getDurationFromDateTillNowMilliseconds, + getNumberFormattedToDecimalPlace, +} from 'components/AmplitudeAnalytics/utils' import AnimatedDropdown from 'components/AnimatedDropdown' import Card, { OutlineCard } from 'components/Card' import { AutoColumn } from 'components/Column' @@ -122,10 +126,16 @@ interface SwapDetailsInlineProps { showInverted: boolean setShowInverted: React.Dispatch> allowedSlippage: Percent + setSwapQuoteReceivedDate: (date: Date) => void } -const formatAnalyticsEventProperties = (trade: InterfaceTrade) => { +const formatAnalyticsEventProperties = ( + trade: InterfaceTrade, + fetchingQuoteStartTime: Date | undefined, + setSwapQuoteReceivedDate: (date: Date) => void +) => { const lpFeePercent = trade ? computeRealizedLPFeePercent(trade) : undefined + setSwapQuoteReceivedDate(new Date()) return { token_in_symbol: trade.inputAmount.currency.symbol, token_out_symbol: trade.outputAmount.currency.symbol, @@ -143,7 +153,9 @@ const formatAnalyticsEventProperties = (trade: InterfaceTrade() useEffect(() => { + if (loading || syncing) setFetchingQuoteStartTime(new Date()) if (isFirstPriceFetch && syncing) setIsFirstPriceFetch(false) - }, [isFirstPriceFetch, syncing]) + }, [isFirstPriceFetch, syncing, loading]) return ( @@ -209,7 +224,7 @@ export default function SwapDetailsDropdown({ ({ estimated_network_fee_usd: trade.gasUseEstimateUSD ? getNumberFormattedToDecimalPlace(trade.gasUseEstimateUSD, 2) : undefined, transaction_hash: txHash, - transaction_deadline_seconds: getDurationTillTimestampSinceEpoch(transactionDeadlineSecondsSinceEpoch), + transaction_deadline_seconds: getDurationTillTimestampSinceEpochSeconds(transactionDeadlineSecondsSinceEpoch), token_in_amount_usd: tokenInAmountUsd ? parseFloat(tokenInAmountUsd) : undefined, token_out_amount_usd: tokenOutAmountUsd ? parseFloat(tokenOutAmountUsd) : undefined, token_in_address: trade.inputAmount.currency.isToken ? trade.inputAmount.currency.address : undefined, @@ -65,6 +68,9 @@ const formatAnalyticsEventProperties = ({ trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId ? trade.inputAmount.currency.chainId : undefined, + duration_from_first_quote_to_swap_submission_milliseconds: swapQuoteReceivedDate + ? getDurationFromDateTillNowMilliseconds(swapQuoteReceivedDate) + : undefined, // TODO(lynnshaoyu): implement duration_from_first_quote_to_swap_submission_seconds }) @@ -75,6 +81,7 @@ export default function SwapModalFooter({ onConfirm, swapErrorMessage, disabledConfirm, + swapQuoteReceivedDate, }: { trade: InterfaceTrade txHash: string | undefined @@ -82,6 +89,7 @@ export default function SwapModalFooter({ onConfirm: () => void swapErrorMessage: ReactNode | undefined disabledConfirm: boolean + swapQuoteReceivedDate: Date | undefined }) { const transactionDeadlineSecondsSinceEpoch = useTransactionDeadline()?.toNumber() // in seconds since epoch const isAutoSlippage = useUserSlippageTolerance() === 'auto' @@ -107,6 +115,7 @@ export default function SwapModalFooter({ tokenInAmountUsd, tokenOutAmountUsd, lpFeePercent, + swapQuoteReceivedDate, })} > (false) + const [swapQuoteReceivedDate, setSwapQuoteReceivedDate] = useState() // warnings on the greater of fiat value price impact and execution price impact const priceImpactSeverity = useMemo(() => { @@ -436,6 +437,7 @@ export default function Swap() { onConfirm={handleSwap} swapErrorMessage={swapErrorMessage} onDismiss={handleConfirmDismiss} + swapQuoteReceivedDate={swapQuoteReceivedDate} /> @@ -524,6 +526,7 @@ export default function Swap() { showInverted={showInverted} setShowInverted={setShowInverted} allowedSlippage={allowedSlippage} + setSwapQuoteReceivedDate={setSwapQuoteReceivedDate} /> )}
From c01803ff2b344bdefcc721f012728bb289b8617f Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Tue, 26 Jul 2022 16:03:51 -0400 Subject: [PATCH 2/8] remove absolute value in date calc --- src/components/AmplitudeAnalytics/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AmplitudeAnalytics/utils.ts b/src/components/AmplitudeAnalytics/utils.ts index eec5822723b..eda76ad3e83 100644 --- a/src/components/AmplitudeAnalytics/utils.ts +++ b/src/components/AmplitudeAnalytics/utils.ts @@ -6,7 +6,7 @@ export const getDurationTillTimestampSinceEpochSeconds = (futureTimestampSinceEp } export const getDurationFromDateTillNowMilliseconds = (date: Date): number => { - return Math.abs(new Date().getUTCMilliseconds() - date.getUTCMilliseconds()) + return new Date().getUTCMilliseconds() - date.getUTCMilliseconds() } export const getNumberFormattedToDecimalPlace = ( From 0c0b7afcedccfce24940ae9d476e337bc59e0cb2 Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Wed, 27 Jul 2022 12:19:49 -0400 Subject: [PATCH 3/8] all the events are now logged properly plus changed native token address to NATIVE --- .../AmplitudeAnalytics/constants.ts | 3 +- src/components/AmplitudeAnalytics/utils.ts | 4 +- src/components/SearchModal/CommonBases.tsx | 16 ++-- src/components/SearchModal/CurrencySearch.tsx | 8 +- src/components/swap/SwapDetailsDropdown.tsx | 64 ++------------- src/components/swap/SwapModalFooter.tsx | 7 +- src/pages/Swap/index.tsx | 81 ++++++++++++++++++- 7 files changed, 101 insertions(+), 82 deletions(-) diff --git a/src/components/AmplitudeAnalytics/constants.ts b/src/components/AmplitudeAnalytics/constants.ts index 5d00b697eca..f5bd9afaa9e 100644 --- a/src/components/AmplitudeAnalytics/constants.ts +++ b/src/components/AmplitudeAnalytics/constants.ts @@ -38,6 +38,8 @@ export enum WALLET_CONNECTION_RESULT { FAILED = 'Failed', } +export const NATIVE_CHAIN_ADDRESS = 'NATIVE' + /** * Known pages in the app. Highest order context. */ @@ -81,7 +83,6 @@ export const enum ElementName { SWAP_BUTTON = 'swap-button', SWAP_DETAILS_DROPDOWN = 'swap-details-dropdown', SWAP_TOKENS_REVERSE_ARROW_BUTTON = 'swap-tokens-reverse-arrow-button', - SWAP_TRADE_PRICE_ROW = 'swap-trade-price-row', TOKEN_SELECTOR_ROW = 'token-selector-row', WALLET_TYPE_OPTION = 'wallet-type-option', // alphabetize additional element names. diff --git a/src/components/AmplitudeAnalytics/utils.ts b/src/components/AmplitudeAnalytics/utils.ts index eda76ad3e83..584130948c1 100644 --- a/src/components/AmplitudeAnalytics/utils.ts +++ b/src/components/AmplitudeAnalytics/utils.ts @@ -5,8 +5,8 @@ export const getDurationTillTimestampSinceEpochSeconds = (futureTimestampSinceEp return futureTimestampSinceEpoch - new Date().getTime() / 1000 } -export const getDurationFromDateTillNowMilliseconds = (date: Date): number => { - return new Date().getUTCMilliseconds() - date.getUTCMilliseconds() +export const getDurationFromDateTillNowMilliseconds = (start: Date): number => { + return new Date().getTime() - start.getTime() } export const getNumberFormattedToDecimalPlace = ( diff --git a/src/components/SearchModal/CommonBases.tsx b/src/components/SearchModal/CommonBases.tsx index d27485bdec0..95cff3234da 100644 --- a/src/components/SearchModal/CommonBases.tsx +++ b/src/components/SearchModal/CommonBases.tsx @@ -1,5 +1,5 @@ -import { Currency, Token } from '@uniswap/sdk-core' -import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants' +import { Currency } from '@uniswap/sdk-core' +import { ElementName, Event, EventName, NATIVE_CHAIN_ADDRESS } from 'components/AmplitudeAnalytics/constants' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' import { AutoColumn } from 'components/Column' import CurrencyLogo from 'components/CurrencyLogo' @@ -33,15 +33,10 @@ const BaseWrapper = styled.div<{ disable?: boolean }>` filter: ${({ disable }) => disable && 'grayscale(1)'}; ` -const formatAnalyticsEventProperties = ( - currency: Currency, - tokenAddress: string | undefined, - searchQuery: string, - isAddressSearch: string | false -) => ({ +const formatAnalyticsEventProperties = (currency: Currency, searchQuery: string, isAddressSearch: string | false) => ({ token_symbol: currency?.symbol, token_chain_id: currency?.chainId, - ...(tokenAddress ? { token_address: tokenAddress } : {}), + token_address: currency.isNative ? NATIVE_CHAIN_ADDRESS : currency.address, is_suggested_token: true, is_selected_from_list: false, is_imported_by_user: false, @@ -70,13 +65,12 @@ export default function CommonBases({ {bases.map((currency: Currency) => { const isSelected = selectedCurrency?.equals(currency) - const tokenAddress = currency instanceof Token ? currency?.address : undefined return ( diff --git a/src/components/SearchModal/CurrencySearch.tsx b/src/components/SearchModal/CurrencySearch.tsx index 216acc884da..515f44345f9 100644 --- a/src/components/SearchModal/CurrencySearch.tsx +++ b/src/components/SearchModal/CurrencySearch.tsx @@ -191,8 +191,8 @@ export function CurrencySearch({ }, []) return ( - - + + @@ -270,7 +270,7 @@ export function CurrencySearch({ - - + + ) } diff --git a/src/components/swap/SwapDetailsDropdown.tsx b/src/components/swap/SwapDetailsDropdown.tsx index 6b1728e8d53..99a414bce9e 100644 --- a/src/components/swap/SwapDetailsDropdown.tsx +++ b/src/components/swap/SwapDetailsDropdown.tsx @@ -2,13 +2,7 @@ import { Trans } from '@lingui/macro' import { Currency, Percent, TradeType } from '@uniswap/sdk-core' import { useWeb3React } from '@web3-react/core' import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants' -import { Trace } from 'components/AmplitudeAnalytics/Trace' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' -import { - formatPercentInBasisPointsNumber, - getDurationFromDateTillNowMilliseconds, - getNumberFormattedToDecimalPlace, -} from 'components/AmplitudeAnalytics/utils' import AnimatedDropdown from 'components/AnimatedDropdown' import Card, { OutlineCard } from 'components/Card' import { AutoColumn } from 'components/Column' @@ -17,15 +11,13 @@ import Row, { RowBetween, RowFixed } from 'components/Row' import { MouseoverTooltipContent } from 'components/Tooltip' import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains' import { darken } from 'polished' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { ChevronDown, Info } from 'react-feather' import { InterfaceTrade } from 'state/routing/types' import styled, { keyframes, useTheme } from 'styled-components/macro' import { HideSmall, ThemedText } from 'theme' -import { computeRealizedLPFeePercent } from 'utils/prices' import { AdvancedSwapDetails } from './AdvancedSwapDetails' -import { getPriceImpactPercent } from './AdvancedSwapDetails' import GasEstimateBadge from './GasEstimateBadge' import { ResponsiveTooltipContainer } from './styleds' import SwapRoute from './SwapRoute' @@ -129,36 +121,6 @@ interface SwapDetailsInlineProps { setSwapQuoteReceivedDate: (date: Date) => void } -const formatAnalyticsEventProperties = ( - trade: InterfaceTrade, - fetchingQuoteStartTime: Date | undefined, - setSwapQuoteReceivedDate: (date: Date) => void -) => { - const lpFeePercent = trade ? computeRealizedLPFeePercent(trade) : undefined - setSwapQuoteReceivedDate(new Date()) - return { - token_in_symbol: trade.inputAmount.currency.symbol, - token_out_symbol: trade.outputAmount.currency.symbol, - token_in_address: trade.inputAmount.currency.isToken ? trade.inputAmount.currency.address : undefined, - token_out_address: trade.outputAmount.currency.isToken ? trade.outputAmount.currency.address : undefined, - price_impact_basis_points: lpFeePercent - ? formatPercentInBasisPointsNumber(getPriceImpactPercent(lpFeePercent, trade)) - : undefined, - estimated_network_fee_usd: trade.gasUseEstimateUSD - ? getNumberFormattedToDecimalPlace(trade.gasUseEstimateUSD, 2) - : undefined, - chain_id: - trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId - ? trade.inputAmount.currency.chainId - : undefined, - token_in_amount: getNumberFormattedToDecimalPlace(trade.inputAmount, trade.inputAmount.currency.decimals), - token_out_amount: getNumberFormattedToDecimalPlace(trade.outputAmount, trade.outputAmount.currency.decimals), - quote_latency_milliseconds: fetchingQuoteStartTime - ? getDurationFromDateTillNowMilliseconds(fetchingQuoteStartTime) - : undefined, - } -} - export default function SwapDetailsDropdown({ trade, syncing, @@ -171,13 +133,6 @@ export default function SwapDetailsDropdown({ const theme = useTheme() const { chainId } = useWeb3React() const [showDetails, setShowDetails] = useState(false) - const [isFirstPriceFetch, setIsFirstPriceFetch] = useState(true) - const [fetchingQuoteStartTime, setFetchingQuoteStartTime] = useState() - - useEffect(() => { - if (loading || syncing) setFetchingQuoteStartTime(new Date()) - if (isFirstPriceFetch && syncing) setIsFirstPriceFetch(false) - }, [isFirstPriceFetch, syncing, loading]) return ( @@ -221,18 +176,11 @@ export default function SwapDetailsDropdown({ )} {trade ? ( - - - + ) : loading || syncing ? ( diff --git a/src/components/swap/SwapModalFooter.tsx b/src/components/swap/SwapModalFooter.tsx index 19f4c185098..067e1d5d041 100644 --- a/src/components/swap/SwapModalFooter.tsx +++ b/src/components/swap/SwapModalFooter.tsx @@ -1,6 +1,6 @@ import { Trans } from '@lingui/macro' import { Currency, Percent, TradeType } from '@uniswap/sdk-core' -import { ElementName, EventName } from 'components/AmplitudeAnalytics/constants' +import { ElementName, EventName, NATIVE_CHAIN_ADDRESS } from 'components/AmplitudeAnalytics/constants' import { Event } from 'components/AmplitudeAnalytics/constants' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' import { @@ -54,8 +54,8 @@ const formatAnalyticsEventProperties = ({ transaction_deadline_seconds: getDurationTillTimestampSinceEpochSeconds(transactionDeadlineSecondsSinceEpoch), token_in_amount_usd: tokenInAmountUsd ? parseFloat(tokenInAmountUsd) : undefined, token_out_amount_usd: tokenOutAmountUsd ? parseFloat(tokenOutAmountUsd) : undefined, - token_in_address: trade.inputAmount.currency.isToken ? trade.inputAmount.currency.address : undefined, - token_out_address: trade.outputAmount.currency.isToken ? trade.outputAmount.currency.address : undefined, + token_in_address: trade.inputAmount.currency.isNative ? NATIVE_CHAIN_ADDRESS : trade.inputAmount.currency.address, + token_out_address: trade.outputAmount.currency.isNative ? NATIVE_CHAIN_ADDRESS : trade.outputAmount.currency.address, token_in_symbol: trade.inputAmount.currency.symbol, token_out_symbol: trade.outputAmount.currency.symbol, token_in_amount: getNumberFormattedToDecimalPlace(trade.inputAmount, trade.inputAmount.currency.decimals), @@ -71,7 +71,6 @@ const formatAnalyticsEventProperties = ({ duration_from_first_quote_to_swap_submission_milliseconds: swapQuoteReceivedDate ? getDurationFromDateTillNowMilliseconds(swapQuoteReceivedDate) : undefined, - // TODO(lynnshaoyu): implement duration_from_first_quote_to_swap_submission_seconds }) export default function SwapModalFooter({ diff --git a/src/pages/Swap/index.tsx b/src/pages/Swap/index.tsx index 42f1d312ddc..44e3d2b40a8 100644 --- a/src/pages/Swap/index.tsx +++ b/src/pages/Swap/index.tsx @@ -4,12 +4,25 @@ import { Currency, CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core' import { Trade as V2Trade } from '@uniswap/v2-sdk' import { Trade as V3Trade } from '@uniswap/v3-sdk' import { useWeb3React } from '@web3-react/core' -import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants' -import { PageName, SectionName } from 'components/AmplitudeAnalytics/constants' +import { sendAnalyticsEvent } from 'components/AmplitudeAnalytics' +import { + ElementName, + Event, + EventName, + NATIVE_CHAIN_ADDRESS, + PageName, + SectionName, +} from 'components/AmplitudeAnalytics/constants' import { Trace } from 'components/AmplitudeAnalytics/Trace' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' +import { + formatPercentInBasisPointsNumber, + getDurationFromDateTillNowMilliseconds, + getNumberFormattedToDecimalPlace, +} from 'components/AmplitudeAnalytics/utils' import { sendEvent } from 'components/analytics' import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert' +import { getPriceImpactPercent } from 'components/swap/AdvancedSwapDetails' import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown' import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter' import { MouseoverTooltip } from 'components/Tooltip' @@ -61,6 +74,7 @@ import { useExpertModeManager } from '../../state/user/hooks' import { LinkStyledButton, ThemedText } from '../../theme' import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact' import { maxAmountSpend } from '../../utils/maxAmountSpend' +import { computeRealizedLPFeePercent } from '../../utils/prices' import { warningSeverity } from '../../utils/prices' import { supportedChainId } from '../../utils/supportedChainId' import AppBody from '../AppBody' @@ -78,10 +92,42 @@ export function getIsValidSwapQuote( return !!swapInputError && !!trade && (tradeState === TradeState.VALID || tradeState === TradeState.SYNCING) } +const formatAnalyticsEventProperties = ( + trade: InterfaceTrade, + fetchingSwapQuoteStartTime: Date | undefined +) => { + const lpFeePercent = trade ? computeRealizedLPFeePercent(trade) : undefined + return { + token_in_symbol: trade.inputAmount.currency.symbol, + token_out_symbol: trade.outputAmount.currency.symbol, + token_in_address: trade.inputAmount.currency.isNative ? NATIVE_CHAIN_ADDRESS : trade.inputAmount.currency.address, + token_out_address: trade.outputAmount.currency.isNative + ? NATIVE_CHAIN_ADDRESS + : trade.outputAmount.currency.address, + price_impact_basis_points: lpFeePercent + ? formatPercentInBasisPointsNumber(getPriceImpactPercent(lpFeePercent, trade)) + : undefined, + estimated_network_fee_usd: trade.gasUseEstimateUSD + ? getNumberFormattedToDecimalPlace(trade.gasUseEstimateUSD, 2) + : undefined, + chain_id: + trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId + ? trade.inputAmount.currency.chainId + : undefined, + token_in_amount: getNumberFormattedToDecimalPlace(trade.inputAmount, trade.inputAmount.currency.decimals), + token_out_amount: getNumberFormattedToDecimalPlace(trade.outputAmount, trade.outputAmount.currency.decimals), + quote_latency_milliseconds: fetchingSwapQuoteStartTime + ? getDurationFromDateTillNowMilliseconds(fetchingSwapQuoteStartTime) + : undefined, + } +} + export default function Swap() { const navigate = useNavigate() const { account, chainId } = useWeb3React() const loadedUrlParams = useDefaultsFromURLSearch() + const [newSwapQuoteNeedsLogging, setNewSwapQuoteNeedsLogging] = useState(true) + const [fetchingSwapQuoteStartTime, setFetchingSwapQuoteStartTime] = useState() // token warning stuff const [loadedInputCurrency, loadedOutputCurrency] = [ @@ -413,6 +459,37 @@ export default function Swap() { const priceImpactTooHigh = priceImpactSeverity > 3 && !isExpertMode + useEffect(() => { + const now = new Date() + // If a trade exists, and we need to log the receipt of this new swap quote: + if (newSwapQuoteNeedsLogging && !!trade) { + // Set the current datetime as the time of receipt of latest swap quote. + setSwapQuoteReceivedDate(now) + // Log swap quote. + sendAnalyticsEvent( + EventName.SWAP_QUOTE_RECEIVED, + formatAnalyticsEventProperties(trade, fetchingSwapQuoteStartTime) + ) + // Latest swap quote has just been logged, so we don't need to log the current trade anymore + // unless user inputs change again and a new trade is in the process of being generated. + setNewSwapQuoteNeedsLogging(false) + // New quote is not being fetched, so set start time of quote fetch to undefined. + setFetchingSwapQuoteStartTime(undefined) + } + // If another swap quote is being loaded based on changed user inputs: + if (routeIsLoading) { + setNewSwapQuoteNeedsLogging(true) + if (fetchingSwapQuoteStartTime === undefined) setFetchingSwapQuoteStartTime(now) + } + }, [ + newSwapQuoteNeedsLogging, + routeIsSyncing, + routeIsLoading, + fetchingSwapQuoteStartTime, + trade, + setSwapQuoteReceivedDate, + ]) + return ( <> From 9fd665163715626bda9f65f8e16869da78ebb758 Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Wed, 27 Jul 2022 12:23:19 -0400 Subject: [PATCH 4/8] add documentation line --- src/pages/Swap/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/Swap/index.tsx b/src/pages/Swap/index.tsx index 44e3d2b40a8..18522dead2a 100644 --- a/src/pages/Swap/index.tsx +++ b/src/pages/Swap/index.tsx @@ -459,6 +459,7 @@ export default function Swap() { const priceImpactTooHigh = priceImpactSeverity > 3 && !isExpertMode + // Handle time based logging events and event properties. useEffect(() => { const now = new Date() // If a trade exists, and we need to log the receipt of this new swap quote: From 2f33238d39a68d815cbc5e3fe7a30d14d6380eaa Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Wed, 27 Jul 2022 12:28:15 -0400 Subject: [PATCH 5/8] remove unnecessary prop --- src/components/swap/SwapDetailsDropdown.tsx | 2 -- src/pages/Swap/index.tsx | 1 - 2 files changed, 3 deletions(-) diff --git a/src/components/swap/SwapDetailsDropdown.tsx b/src/components/swap/SwapDetailsDropdown.tsx index 99a414bce9e..2ce1a823e8b 100644 --- a/src/components/swap/SwapDetailsDropdown.tsx +++ b/src/components/swap/SwapDetailsDropdown.tsx @@ -118,7 +118,6 @@ interface SwapDetailsInlineProps { showInverted: boolean setShowInverted: React.Dispatch> allowedSlippage: Percent - setSwapQuoteReceivedDate: (date: Date) => void } export default function SwapDetailsDropdown({ @@ -128,7 +127,6 @@ export default function SwapDetailsDropdown({ showInverted, setShowInverted, allowedSlippage, - setSwapQuoteReceivedDate, }: SwapDetailsInlineProps) { const theme = useTheme() const { chainId } = useWeb3React() diff --git a/src/pages/Swap/index.tsx b/src/pages/Swap/index.tsx index 18522dead2a..ab5d9c76f7d 100644 --- a/src/pages/Swap/index.tsx +++ b/src/pages/Swap/index.tsx @@ -604,7 +604,6 @@ export default function Swap() { showInverted={showInverted} setShowInverted={setShowInverted} allowedSlippage={allowedSlippage} - setSwapQuoteReceivedDate={setSwapQuoteReceivedDate} /> )}
From ededb290642cf9ff92c9278a7fc72ef104c835a1 Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Thu, 28 Jul 2022 15:14:55 -0400 Subject: [PATCH 6/8] respond to vm comments --- .../AmplitudeAnalytics/constants.ts | 2 +- src/components/AmplitudeAnalytics/utils.ts | 8 +++-- src/components/swap/SwapModalFooter.tsx | 14 ++++---- src/pages/Swap/index.tsx | 32 +++++++------------ 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/src/components/AmplitudeAnalytics/constants.ts b/src/components/AmplitudeAnalytics/constants.ts index f5bd9afaa9e..4eac62275bd 100644 --- a/src/components/AmplitudeAnalytics/constants.ts +++ b/src/components/AmplitudeAnalytics/constants.ts @@ -38,7 +38,7 @@ export enum WALLET_CONNECTION_RESULT { FAILED = 'Failed', } -export const NATIVE_CHAIN_ADDRESS = 'NATIVE' +export const NATIVE_CHAIN_ID = 'NATIVE' /** * Known pages in the app. Highest order context. diff --git a/src/components/AmplitudeAnalytics/utils.ts b/src/components/AmplitudeAnalytics/utils.ts index 584130948c1..574b04e1bc6 100644 --- a/src/components/AmplitudeAnalytics/utils.ts +++ b/src/components/AmplitudeAnalytics/utils.ts @@ -1,17 +1,21 @@ import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' +import { NATIVE_CHAIN_ID } from './constants' + export const getDurationTillTimestampSinceEpochSeconds = (futureTimestampSinceEpoch?: number): number | undefined => { if (!futureTimestampSinceEpoch) return undefined return futureTimestampSinceEpoch - new Date().getTime() / 1000 } -export const getDurationFromDateTillNowMilliseconds = (start: Date): number => { +export const getDurationFromDateMilliseconds = (start: Date): number => { return new Date().getTime() - start.getTime() } -export const getNumberFormattedToDecimalPlace = ( +export const formatToDecimal = ( intialNumberObject: Percent | CurrencyAmount, decimalPlace: number ): number => parseFloat(intialNumberObject.toFixed(decimalPlace)) +export const getTokenAddress = (currency: Currency) => (currency.isNative ? NATIVE_CHAIN_ID : currency.address) + export const formatPercentInBasisPointsNumber = (percent: Percent): number => parseFloat(percent.toFixed(2)) * 100 diff --git a/src/components/swap/SwapModalFooter.tsx b/src/components/swap/SwapModalFooter.tsx index 067e1d5d041..5bdc8f05d27 100644 --- a/src/components/swap/SwapModalFooter.tsx +++ b/src/components/swap/SwapModalFooter.tsx @@ -5,9 +5,9 @@ import { Event } from 'components/AmplitudeAnalytics/constants' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' import { formatPercentInBasisPointsNumber, - getDurationFromDateTillNowMilliseconds, + formatToDecimal, + getDurationFromDateMilliseconds, getDurationTillTimestampSinceEpochSeconds, - getNumberFormattedToDecimalPlace, } from 'components/AmplitudeAnalytics/utils' import { useStablecoinValue } from 'hooks/useStablecoinPrice' import useTransactionDeadline from 'hooks/useTransactionDeadline' @@ -47,9 +47,7 @@ const formatAnalyticsEventProperties = ({ lpFeePercent, swapQuoteReceivedDate, }: AnalyticsEventProps) => ({ - estimated_network_fee_usd: trade.gasUseEstimateUSD - ? getNumberFormattedToDecimalPlace(trade.gasUseEstimateUSD, 2) - : undefined, + estimated_network_fee_usd: trade.gasUseEstimateUSD ? formatToDecimal(trade.gasUseEstimateUSD, 2) : undefined, transaction_hash: txHash, transaction_deadline_seconds: getDurationTillTimestampSinceEpochSeconds(transactionDeadlineSecondsSinceEpoch), token_in_amount_usd: tokenInAmountUsd ? parseFloat(tokenInAmountUsd) : undefined, @@ -58,8 +56,8 @@ const formatAnalyticsEventProperties = ({ token_out_address: trade.outputAmount.currency.isNative ? NATIVE_CHAIN_ADDRESS : trade.outputAmount.currency.address, token_in_symbol: trade.inputAmount.currency.symbol, token_out_symbol: trade.outputAmount.currency.symbol, - token_in_amount: getNumberFormattedToDecimalPlace(trade.inputAmount, trade.inputAmount.currency.decimals), - token_out_amount: getNumberFormattedToDecimalPlace(trade.outputAmount, trade.outputAmount.currency.decimals), + token_in_amount: formatToDecimal(trade.inputAmount, trade.inputAmount.currency.decimals), + token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals), price_impact_basis_points: formatPercentInBasisPointsNumber(getPriceImpactPercent(lpFeePercent, trade)), allowed_slippage_basis_points: formatPercentInBasisPointsNumber(allowedSlippage), is_auto_router_api: isAutoRouterApi, @@ -69,7 +67,7 @@ const formatAnalyticsEventProperties = ({ ? trade.inputAmount.currency.chainId : undefined, duration_from_first_quote_to_swap_submission_milliseconds: swapQuoteReceivedDate - ? getDurationFromDateTillNowMilliseconds(swapQuoteReceivedDate) + ? getDurationFromDateMilliseconds(swapQuoteReceivedDate) : undefined, }) diff --git a/src/pages/Swap/index.tsx b/src/pages/Swap/index.tsx index ab5d9c76f7d..364d695a745 100644 --- a/src/pages/Swap/index.tsx +++ b/src/pages/Swap/index.tsx @@ -5,20 +5,14 @@ import { Trade as V2Trade } from '@uniswap/v2-sdk' import { Trade as V3Trade } from '@uniswap/v3-sdk' import { useWeb3React } from '@web3-react/core' import { sendAnalyticsEvent } from 'components/AmplitudeAnalytics' -import { - ElementName, - Event, - EventName, - NATIVE_CHAIN_ADDRESS, - PageName, - SectionName, -} from 'components/AmplitudeAnalytics/constants' +import { ElementName, Event, EventName, PageName, SectionName } from 'components/AmplitudeAnalytics/constants' import { Trace } from 'components/AmplitudeAnalytics/Trace' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' import { formatPercentInBasisPointsNumber, - getDurationFromDateTillNowMilliseconds, - getNumberFormattedToDecimalPlace, + formatToDecimal, + getDurationFromDateMilliseconds, + getTokenAddress, } from 'components/AmplitudeAnalytics/utils' import { sendEvent } from 'components/analytics' import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert' @@ -100,24 +94,20 @@ const formatAnalyticsEventProperties = ( return { token_in_symbol: trade.inputAmount.currency.symbol, token_out_symbol: trade.outputAmount.currency.symbol, - token_in_address: trade.inputAmount.currency.isNative ? NATIVE_CHAIN_ADDRESS : trade.inputAmount.currency.address, - token_out_address: trade.outputAmount.currency.isNative - ? NATIVE_CHAIN_ADDRESS - : trade.outputAmount.currency.address, + token_in_address: getTokenAddress(trade.inputAmount.currency), + token_out_address: getTokenAddress(trade.outputAmount.currency), price_impact_basis_points: lpFeePercent ? formatPercentInBasisPointsNumber(getPriceImpactPercent(lpFeePercent, trade)) : undefined, - estimated_network_fee_usd: trade.gasUseEstimateUSD - ? getNumberFormattedToDecimalPlace(trade.gasUseEstimateUSD, 2) - : undefined, + estimated_network_fee_usd: trade.gasUseEstimateUSD ? formatToDecimal(trade.gasUseEstimateUSD, 2) : undefined, chain_id: trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId ? trade.inputAmount.currency.chainId : undefined, - token_in_amount: getNumberFormattedToDecimalPlace(trade.inputAmount, trade.inputAmount.currency.decimals), - token_out_amount: getNumberFormattedToDecimalPlace(trade.outputAmount, trade.outputAmount.currency.decimals), + token_in_amount: formatToDecimal(trade.inputAmount, trade.inputAmount.currency.decimals), + token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals), quote_latency_milliseconds: fetchingSwapQuoteStartTime - ? getDurationFromDateTillNowMilliseconds(fetchingSwapQuoteStartTime) + ? getDurationFromDateMilliseconds(fetchingSwapQuoteStartTime) : undefined, } } @@ -480,7 +470,7 @@ export default function Swap() { // If another swap quote is being loaded based on changed user inputs: if (routeIsLoading) { setNewSwapQuoteNeedsLogging(true) - if (fetchingSwapQuoteStartTime === undefined) setFetchingSwapQuoteStartTime(now) + if (!fetchingSwapQuoteStartTime) setFetchingSwapQuoteStartTime(now) } }, [ newSwapQuoteNeedsLogging, From 5212db2e77d4b901d9d8da3b2c494d7ec4e1a8f4 Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Thu, 28 Jul 2022 15:25:54 -0400 Subject: [PATCH 7/8] merge and rename util method --- src/components/AmplitudeAnalytics/utils.ts | 6 +++--- src/components/SearchModal/CommonBases.tsx | 5 +++-- src/components/swap/SwapModalFooter.tsx | 11 ++++++----- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/components/AmplitudeAnalytics/utils.ts b/src/components/AmplitudeAnalytics/utils.ts index 574b04e1bc6..38ca84ecfd4 100644 --- a/src/components/AmplitudeAnalytics/utils.ts +++ b/src/components/AmplitudeAnalytics/utils.ts @@ -2,9 +2,9 @@ import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' import { NATIVE_CHAIN_ID } from './constants' -export const getDurationTillTimestampSinceEpochSeconds = (futureTimestampSinceEpoch?: number): number | undefined => { - if (!futureTimestampSinceEpoch) return undefined - return futureTimestampSinceEpoch - new Date().getTime() / 1000 +export const getDurationTillTimestampSeconds = (futureTimestampInSecondsSinceEpoch?: number): number | undefined => { + if (!futureTimestampInSecondsSinceEpoch) return undefined + return futureTimestampInSecondsSinceEpoch - new Date().getTime() / 1000 } export const getDurationFromDateMilliseconds = (start: Date): number => { diff --git a/src/components/SearchModal/CommonBases.tsx b/src/components/SearchModal/CommonBases.tsx index 95cff3234da..ad410bf1995 100644 --- a/src/components/SearchModal/CommonBases.tsx +++ b/src/components/SearchModal/CommonBases.tsx @@ -1,6 +1,7 @@ import { Currency } from '@uniswap/sdk-core' -import { ElementName, Event, EventName, NATIVE_CHAIN_ADDRESS } from 'components/AmplitudeAnalytics/constants' +import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' +import { getTokenAddress } from 'components/AmplitudeAnalytics/utils' import { AutoColumn } from 'components/Column' import CurrencyLogo from 'components/CurrencyLogo' import { AutoRow } from 'components/Row' @@ -36,7 +37,7 @@ const BaseWrapper = styled.div<{ disable?: boolean }>` const formatAnalyticsEventProperties = (currency: Currency, searchQuery: string, isAddressSearch: string | false) => ({ token_symbol: currency?.symbol, token_chain_id: currency?.chainId, - token_address: currency.isNative ? NATIVE_CHAIN_ADDRESS : currency.address, + token_address: getTokenAddress(currency), is_suggested_token: true, is_selected_from_list: false, is_imported_by_user: false, diff --git a/src/components/swap/SwapModalFooter.tsx b/src/components/swap/SwapModalFooter.tsx index 5bdc8f05d27..98c63d982d1 100644 --- a/src/components/swap/SwapModalFooter.tsx +++ b/src/components/swap/SwapModalFooter.tsx @@ -1,13 +1,14 @@ import { Trans } from '@lingui/macro' import { Currency, Percent, TradeType } from '@uniswap/sdk-core' -import { ElementName, EventName, NATIVE_CHAIN_ADDRESS } from 'components/AmplitudeAnalytics/constants' +import { ElementName, EventName } from 'components/AmplitudeAnalytics/constants' import { Event } from 'components/AmplitudeAnalytics/constants' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' import { formatPercentInBasisPointsNumber, formatToDecimal, getDurationFromDateMilliseconds, - getDurationTillTimestampSinceEpochSeconds, + getDurationTillTimestampSeconds, + getTokenAddress, } from 'components/AmplitudeAnalytics/utils' import { useStablecoinValue } from 'hooks/useStablecoinPrice' import useTransactionDeadline from 'hooks/useTransactionDeadline' @@ -49,11 +50,11 @@ const formatAnalyticsEventProperties = ({ }: AnalyticsEventProps) => ({ estimated_network_fee_usd: trade.gasUseEstimateUSD ? formatToDecimal(trade.gasUseEstimateUSD, 2) : undefined, transaction_hash: txHash, - transaction_deadline_seconds: getDurationTillTimestampSinceEpochSeconds(transactionDeadlineSecondsSinceEpoch), + transaction_deadline_seconds: getDurationTillTimestampSeconds(transactionDeadlineSecondsSinceEpoch), token_in_amount_usd: tokenInAmountUsd ? parseFloat(tokenInAmountUsd) : undefined, token_out_amount_usd: tokenOutAmountUsd ? parseFloat(tokenOutAmountUsd) : undefined, - token_in_address: trade.inputAmount.currency.isNative ? NATIVE_CHAIN_ADDRESS : trade.inputAmount.currency.address, - token_out_address: trade.outputAmount.currency.isNative ? NATIVE_CHAIN_ADDRESS : trade.outputAmount.currency.address, + token_in_address: getTokenAddress(trade.inputAmount.currency), + token_out_address: getTokenAddress(trade.outputAmount.currency), token_in_symbol: trade.inputAmount.currency.symbol, token_out_symbol: trade.outputAmount.currency.symbol, token_in_amount: formatToDecimal(trade.inputAmount, trade.inputAmount.currency.decimals), From 769578416ec6be1b4702ec4141d99447f6537a70 Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Thu, 28 Jul 2022 15:32:53 -0400 Subject: [PATCH 8/8] respond to vm comments again --- src/components/AmplitudeAnalytics/utils.ts | 2 +- src/components/swap/SwapModalFooter.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/AmplitudeAnalytics/utils.ts b/src/components/AmplitudeAnalytics/utils.ts index 38ca84ecfd4..4126d6b5d96 100644 --- a/src/components/AmplitudeAnalytics/utils.ts +++ b/src/components/AmplitudeAnalytics/utils.ts @@ -2,7 +2,7 @@ import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' import { NATIVE_CHAIN_ID } from './constants' -export const getDurationTillTimestampSeconds = (futureTimestampInSecondsSinceEpoch?: number): number | undefined => { +export const getDurationUntilTimestampSeconds = (futureTimestampInSecondsSinceEpoch?: number): number | undefined => { if (!futureTimestampInSecondsSinceEpoch) return undefined return futureTimestampInSecondsSinceEpoch - new Date().getTime() / 1000 } diff --git a/src/components/swap/SwapModalFooter.tsx b/src/components/swap/SwapModalFooter.tsx index 98c63d982d1..2c3072e4f0b 100644 --- a/src/components/swap/SwapModalFooter.tsx +++ b/src/components/swap/SwapModalFooter.tsx @@ -7,7 +7,7 @@ import { formatPercentInBasisPointsNumber, formatToDecimal, getDurationFromDateMilliseconds, - getDurationTillTimestampSeconds, + getDurationUntilTimestampSeconds, getTokenAddress, } from 'components/AmplitudeAnalytics/utils' import { useStablecoinValue } from 'hooks/useStablecoinPrice' @@ -50,7 +50,7 @@ const formatAnalyticsEventProperties = ({ }: AnalyticsEventProps) => ({ estimated_network_fee_usd: trade.gasUseEstimateUSD ? formatToDecimal(trade.gasUseEstimateUSD, 2) : undefined, transaction_hash: txHash, - transaction_deadline_seconds: getDurationTillTimestampSeconds(transactionDeadlineSecondsSinceEpoch), + transaction_deadline_seconds: getDurationUntilTimestampSeconds(transactionDeadlineSecondsSinceEpoch), token_in_amount_usd: tokenInAmountUsd ? parseFloat(tokenInAmountUsd) : undefined, token_out_amount_usd: tokenOutAmountUsd ? parseFloat(tokenOutAmountUsd) : undefined, token_in_address: getTokenAddress(trade.inputAmount.currency),