Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/components/AmplitudeAnalytics/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export enum WALLET_CONNECTION_RESULT {
FAILED = 'Failed',
}

export const NATIVE_CHAIN_ID = 'NATIVE'

export enum SWAP_PRICE_UPDATE_USER_RESPONSE {
ACCEPTED = 'Accepted',
REJECTED = 'Rejected',
Expand Down Expand Up @@ -89,7 +91,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.
Expand Down
18 changes: 13 additions & 5 deletions src/components/AmplitudeAnalytics/utils.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'

export const getDurationTillTimestampSinceEpoch = (futureTimestampSinceEpoch?: number): number | undefined => {
if (!futureTimestampSinceEpoch) return undefined
return futureTimestampSinceEpoch - new Date().getTime() / 1000
import { NATIVE_CHAIN_ID } from './constants'

export const getDurationUntilTimestampSeconds = (futureTimestampInSecondsSinceEpoch?: number): number | undefined => {
if (!futureTimestampInSecondsSinceEpoch) return undefined
return futureTimestampInSecondsSinceEpoch - new Date().getTime() / 1000
}

export const getDurationFromDateMilliseconds = (start: Date): number => {
return new Date().getTime() - start.getTime()
}

export const getNumberFormattedToDecimalPlace = (
export const formatToDecimal = (
intialNumberObject: Percent | CurrencyAmount<Token | Currency>,
decimalPlace: number
): number => parseFloat(intialNumberObject.toFixed(decimalPlace))

export const formatPercentInBasisPointsNumber = (percent: Percent): number => parseFloat(percent.toFixed(6)) * 100
export const getTokenAddress = (currency: Currency) => (currency.isNative ? NATIVE_CHAIN_ID : currency.address)

export const formatPercentInBasisPointsNumber = (percent: Percent): number => parseFloat(percent.toFixed(2)) * 100
15 changes: 5 additions & 10 deletions src/components/SearchModal/CommonBases.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Currency, Token } from '@uniswap/sdk-core'
import { Currency } from '@uniswap/sdk-core'
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'
Expand Down Expand Up @@ -33,15 +34,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: getTokenAddress(currency),
is_suggested_token: true,
is_selected_from_list: false,
is_imported_by_user: false,
Expand Down Expand Up @@ -70,13 +66,12 @@ export default function CommonBases({
<AutoRow gap="4px">
{bases.map((currency: Currency) => {
const isSelected = selectedCurrency?.equals(currency)
const tokenAddress = currency instanceof Token ? currency?.address : undefined

return (
<TraceEvent
events={[Event.onClick, Event.onKeyPress]}
name={EventName.TOKEN_SELECTED}
properties={formatAnalyticsEventProperties(currency, tokenAddress, searchQuery, isAddressSearch)}
properties={formatAnalyticsEventProperties(currency, searchQuery, isAddressSearch)}
element={ElementName.COMMON_BASES_CURRENCY_BUTTON}
key={currencyId(currency)}
>
Expand Down
8 changes: 4 additions & 4 deletions src/components/SearchModal/CurrencySearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,8 +191,8 @@ export function CurrencySearch({
}, [])

return (
<Trace name={EventName.TOKEN_SELECTOR_OPENED} modal={ModalName.TOKEN_SELECTOR} shouldLogImpression={true}>
<ContentWrapper>
<ContentWrapper>
<Trace name={EventName.TOKEN_SELECTOR_OPENED} modal={ModalName.TOKEN_SELECTOR} shouldLogImpression>
<PaddedColumn gap="16px">
<RowBetween>
<Text fontWeight={500} fontSize={16}>
Expand Down Expand Up @@ -270,7 +270,7 @@ export function CurrencySearch({
</ButtonText>
</Row>
</Footer>
</ContentWrapper>
</Trace>
</Trace>
</ContentWrapper>
)
}
5 changes: 4 additions & 1 deletion src/components/swap/ConfirmSwapModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default function ConfirmSwapModal({
isOpen,
attemptingTxn,
txHash,
swapQuoteReceivedDate,
}: {
isOpen: boolean
trade: InterfaceTrade<Currency, Currency, TradeType> | undefined
Expand All @@ -38,6 +39,7 @@ export default function ConfirmSwapModal({
onConfirm: () => void
swapErrorMessage: ReactNode | undefined
onDismiss: () => void
swapQuoteReceivedDate: Date | undefined
}) {
// shouldLogModalCloseEvent lets the child SwapModalHeader component know when modal has been closed
// and an event triggered by modal closing should be logged.
Expand Down Expand Up @@ -75,9 +77,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 = (
Expand Down
51 changes: 6 additions & 45 deletions src/components/swap/SwapDetailsDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +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, getNumberFormattedToDecimalPlace } from 'components/AmplitudeAnalytics/utils'
import AnimatedDropdown from 'components/AnimatedDropdown'
import Card, { OutlineCard } from 'components/Card'
import { AutoColumn } from 'components/Column'
Expand All @@ -13,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'
Expand Down Expand Up @@ -124,29 +120,6 @@ interface SwapDetailsInlineProps {
allowedSlippage: Percent
}

const formatAnalyticsEventProperties = (trade: InterfaceTrade<Currency, Currency, TradeType>) => {
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.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),
// TODO(lynnshaoyu): Implement quote_latency_milliseconds.
}
}

export default function SwapDetailsDropdown({
trade,
syncing,
Expand All @@ -158,11 +131,6 @@ export default function SwapDetailsDropdown({
const theme = useTheme()
const { chainId } = useWeb3React()
const [showDetails, setShowDetails] = useState(false)
const [isFirstPriceFetch, setIsFirstPriceFetch] = useState(true)

useEffect(() => {
if (isFirstPriceFetch && syncing) setIsFirstPriceFetch(false)
}, [isFirstPriceFetch, syncing])

return (
<Wrapper>
Expand Down Expand Up @@ -206,18 +174,11 @@ export default function SwapDetailsDropdown({
)}
{trade ? (
<LoadingOpacityContainer $loading={syncing}>
<Trace
name={EventName.SWAP_QUOTE_RECEIVED}
element={ElementName.SWAP_TRADE_PRICE_ROW}
properties={formatAnalyticsEventProperties(trade)}
shouldLogImpression={!loading && !syncing && isFirstPriceFetch}
>
<TradePrice
price={trade.executionPrice}
showInverted={showInverted}
setShowInverted={setShowInverted}
/>
</Trace>
<TradePrice
price={trade.executionPrice}
showInverted={showInverted}
setShowInverted={setShowInverted}
/>
</LoadingOpacityContainer>
) : loading || syncing ? (
<ThemedText.DeprecatedMain fontSize={14}>
Expand Down
29 changes: 18 additions & 11 deletions src/components/swap/SwapModalFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import { Event } from 'components/AmplitudeAnalytics/constants'
import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent'
import {
formatPercentInBasisPointsNumber,
getDurationTillTimestampSinceEpoch,
getNumberFormattedToDecimalPlace,
formatToDecimal,
getDurationFromDateMilliseconds,
getDurationUntilTimestampSeconds,
getTokenAddress,
} from 'components/AmplitudeAnalytics/utils'
import { useStablecoinValue } from 'hooks/useStablecoinPrice'
import useTransactionDeadline from 'hooks/useTransactionDeadline'
Expand All @@ -31,6 +33,7 @@ interface AnalyticsEventProps {
tokenInAmountUsd: string | undefined
tokenOutAmountUsd: string | undefined
lpFeePercent: Percent
swapQuoteReceivedDate: Date | undefined
}

const formatAnalyticsEventProperties = ({
Expand All @@ -43,20 +46,19 @@ const formatAnalyticsEventProperties = ({
tokenInAmountUsd,
tokenOutAmountUsd,
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: getDurationTillTimestampSinceEpoch(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: trade.inputAmount.currency.isToken ? trade.inputAmount.currency.address : undefined,
token_out_address: trade.outputAmount.currency.isToken ? trade.outputAmount.currency.address : undefined,
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: 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,
Expand All @@ -65,7 +67,9 @@ const formatAnalyticsEventProperties = ({
trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId
? trade.inputAmount.currency.chainId
: undefined,
// TODO(lynnshaoyu): implement duration_from_first_quote_to_swap_submission_seconds
duration_from_first_quote_to_swap_submission_milliseconds: swapQuoteReceivedDate
? getDurationFromDateMilliseconds(swapQuoteReceivedDate)
: undefined,
})

export default function SwapModalFooter({
Expand All @@ -75,13 +79,15 @@ export default function SwapModalFooter({
onConfirm,
swapErrorMessage,
disabledConfirm,
swapQuoteReceivedDate,
}: {
trade: InterfaceTrade<Currency, Currency, TradeType>
txHash: string | undefined
allowedSlippage: Percent
onConfirm: () => void
swapErrorMessage: ReactNode | undefined
disabledConfirm: boolean
swapQuoteReceivedDate: Date | undefined
}) {
const transactionDeadlineSecondsSinceEpoch = useTransactionDeadline()?.toNumber() // in seconds since epoch
const isAutoSlippage = useUserSlippageTolerance() === 'auto'
Expand All @@ -107,6 +113,7 @@ export default function SwapModalFooter({
tokenInAmountUsd,
tokenOutAmountUsd,
lpFeePercent,
swapQuoteReceivedDate,
})}
>
<ButtonError
Expand Down
Loading