Commit 62550a4a authored by lynn's avatar lynn Committed by GitHub

feat: implement swap quote received event (#4165)

* init commit

* add amplitude ts sdk to package.json

* add more comments and documentation

* respond to vm comments

* respond to cmcewen comments

* fix: remove unused constants

* init commit

* adapt to web

* add optional event properties to trace

* correct telemetry to analytics

* init commit

* change telemetry to analytics in doc

* init commit

* fix: respond to cmcewen comments + initialize analytics in app.tsx + add missing return statement

* add element name constant

* init commit

* correct price_impact calculation

* resolve vm comments

* fixes in response to comments

* respond to vm

* use ALL significant digits for token amounts

* init commit

* logged all properties

* create helper function getPriceImpactPercentageNumber

* 4 decimal points for percentages

* price percentage fn

* only log event on FIRST price fetch

* respond to cmcewen comments
parent e01f30c0
...@@ -10,6 +10,7 @@ export enum EventName { ...@@ -10,6 +10,7 @@ export enum EventName {
SWAP_AUTOROUTER_VISUALIZATION_EXPANDED = 'Swap Autorouter Visualization Expanded', SWAP_AUTOROUTER_VISUALIZATION_EXPANDED = 'Swap Autorouter Visualization Expanded',
SWAP_DETAILS_EXPANDED = 'Swap Details Expanded', SWAP_DETAILS_EXPANDED = 'Swap Details Expanded',
SWAP_MAX_TOKEN_AMOUNT_SELECTED = 'Swap Max Token Amount Selected', SWAP_MAX_TOKEN_AMOUNT_SELECTED = 'Swap Max Token Amount Selected',
SWAP_QUOTE_RECEIVED = 'Swap Quote Received',
SWAP_SUBMITTED = 'Swap Submitted', SWAP_SUBMITTED = 'Swap Submitted',
SWAP_TOKENS_REVERSED = 'Swap Tokens Reversed', SWAP_TOKENS_REVERSED = 'Swap Tokens Reversed',
TOKEN_IMPORTED = 'Token Imported', TOKEN_IMPORTED = 'Token Imported',
...@@ -68,6 +69,7 @@ export const enum ElementName { ...@@ -68,6 +69,7 @@ export const enum ElementName {
SWAP_BUTTON = 'swap-button', SWAP_BUTTON = 'swap-button',
SWAP_DETAILS_DROPDOWN = 'swap-details-dropdown', SWAP_DETAILS_DROPDOWN = 'swap-details-dropdown',
SWAP_TOKENS_REVERSE_ARROW_BUTTON = 'swap-tokens-reverse-arrow-button', SWAP_TOKENS_REVERSE_ARROW_BUTTON = 'swap-tokens-reverse-arrow-button',
SWAP_TRADE_PRICE_ROW = 'swap-trade-price-row',
TOKEN_SELECTOR_ROW = 'token-selector-row', TOKEN_SELECTOR_ROW = 'token-selector-row',
WALLET_TYPE_OPTION = 'wallet-type-option', WALLET_TYPE_OPTION = 'wallet-type-option',
// alphabetize additional element names. // alphabetize additional element names.
......
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
}
export const getNumberFormattedToDecimalPlace = (
intialNumberObject: Percent | CurrencyAmount<Token | Currency>,
decimalPlace: number
): number => parseFloat(intialNumberObject.toFixed(decimalPlace))
export const formatPercentInBasisPointsNumber = (percent: Percent): number => parseFloat(percent.toFixed(2)) * 100
...@@ -2,7 +2,9 @@ import { Trans } from '@lingui/macro' ...@@ -2,7 +2,9 @@ import { Trans } from '@lingui/macro'
import { Currency, Percent, TradeType } from '@uniswap/sdk-core' import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants' import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants'
import { Trace } from 'components/AmplitudeAnalytics/Trace'
import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent'
import { formatPercentInBasisPointsNumber, getNumberFormattedToDecimalPlace } from 'components/AmplitudeAnalytics/utils'
import AnimatedDropdown from 'components/AnimatedDropdown' import AnimatedDropdown from 'components/AnimatedDropdown'
import Card, { OutlineCard } from 'components/Card' import Card, { OutlineCard } from 'components/Card'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
...@@ -11,13 +13,15 @@ import Row, { RowBetween, RowFixed } from 'components/Row' ...@@ -11,13 +13,15 @@ import Row, { RowBetween, RowFixed } from 'components/Row'
import { MouseoverTooltipContent } from 'components/Tooltip' import { MouseoverTooltipContent } from 'components/Tooltip'
import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains' import { SUPPORTED_GAS_ESTIMATE_CHAIN_IDS } from 'constants/chains'
import { darken } from 'polished' import { darken } from 'polished'
import { useState } from 'react' import { useEffect, useState } from 'react'
import { ChevronDown, Info } from 'react-feather' import { ChevronDown, Info } from 'react-feather'
import { InterfaceTrade } from 'state/routing/types' import { InterfaceTrade } from 'state/routing/types'
import styled, { keyframes, useTheme } from 'styled-components/macro' import styled, { keyframes, useTheme } from 'styled-components/macro'
import { HideSmall, ThemedText } from 'theme' import { HideSmall, ThemedText } from 'theme'
import { computeRealizedLPFeePercent } from 'utils/prices'
import { AdvancedSwapDetails } from './AdvancedSwapDetails' import { AdvancedSwapDetails } from './AdvancedSwapDetails'
import { getPriceImpactPercent } from './AdvancedSwapDetails'
import GasEstimateBadge from './GasEstimateBadge' import GasEstimateBadge from './GasEstimateBadge'
import { ResponsiveTooltipContainer } from './styleds' import { ResponsiveTooltipContainer } from './styleds'
import SwapRoute from './SwapRoute' import SwapRoute from './SwapRoute'
...@@ -120,6 +124,29 @@ interface SwapDetailsInlineProps { ...@@ -120,6 +124,29 @@ interface SwapDetailsInlineProps {
allowedSlippage: Percent 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({ export default function SwapDetailsDropdown({
trade, trade,
syncing, syncing,
...@@ -131,6 +158,11 @@ export default function SwapDetailsDropdown({ ...@@ -131,6 +158,11 @@ export default function SwapDetailsDropdown({
const theme = useTheme() const theme = useTheme()
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const [showDetails, setShowDetails] = useState(false) const [showDetails, setShowDetails] = useState(false)
const [isFirstPriceFetch, setIsFirstPriceFetch] = useState(true)
useEffect(() => {
if (isFirstPriceFetch && syncing) setIsFirstPriceFetch(false)
}, [isFirstPriceFetch, syncing])
return ( return (
<Wrapper> <Wrapper>
...@@ -174,11 +206,18 @@ export default function SwapDetailsDropdown({ ...@@ -174,11 +206,18 @@ export default function SwapDetailsDropdown({
)} )}
{trade ? ( {trade ? (
<LoadingOpacityContainer $loading={syncing}> <LoadingOpacityContainer $loading={syncing}>
<TradePrice <Trace
price={trade.executionPrice} name={EventName.SWAP_QUOTE_RECEIVED}
showInverted={showInverted} element={ElementName.SWAP_TRADE_PRICE_ROW}
setShowInverted={setShowInverted} properties={formatAnalyticsEventProperties(trade)}
/> shouldLogImpression={!loading && !syncing && isFirstPriceFetch}
>
<TradePrice
price={trade.executionPrice}
showInverted={showInverted}
setShowInverted={setShowInverted}
/>
</Trace>
</LoadingOpacityContainer> </LoadingOpacityContainer>
) : loading || syncing ? ( ) : loading || syncing ? (
<ThemedText.Main fontSize={14}> <ThemedText.Main fontSize={14}>
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core' import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { ElementName, EventName } from 'components/AmplitudeAnalytics/constants' import { ElementName, EventName } from 'components/AmplitudeAnalytics/constants'
import { Event } from 'components/AmplitudeAnalytics/constants' import { Event } from 'components/AmplitudeAnalytics/constants'
import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent'
import {
formatPercentInBasisPointsNumber,
getDurationTillTimestampSinceEpoch,
getNumberFormattedToDecimalPlace,
} from 'components/AmplitudeAnalytics/utils'
import { useStablecoinValue } from 'hooks/useStablecoinPrice' import { useStablecoinValue } from 'hooks/useStablecoinPrice'
import useTransactionDeadline from 'hooks/useTransactionDeadline' import useTransactionDeadline from 'hooks/useTransactionDeadline'
import { ReactNode } from 'react' import { ReactNode } from 'react'
...@@ -16,18 +21,6 @@ import { AutoRow } from '../Row' ...@@ -16,18 +21,6 @@ import { AutoRow } from '../Row'
import { getPriceImpactPercent } from './AdvancedSwapDetails' import { getPriceImpactPercent } from './AdvancedSwapDetails'
import { SwapCallbackError } from './styleds' import { SwapCallbackError } from './styleds'
function getDurationTillTimestampSinceEpoch(futureTimestampSinceEpoch?: number): number | undefined {
if (!futureTimestampSinceEpoch) return undefined
return futureTimestampSinceEpoch - new Date().getTime() / 1000
}
const getNumberFormattedToDecimalPlace = (
intialNumberObject: Percent | CurrencyAmount<Token | Currency>,
decimalPlace: number
): number => parseFloat(intialNumberObject.toFixed(decimalPlace))
const formatPercentInBasisPointsNumber = (percent: Percent): number => parseFloat(percent.toFixed(2)) * 100
interface AnalyticsEventProps { interface AnalyticsEventProps {
trade: InterfaceTrade<Currency, Currency, TradeType> trade: InterfaceTrade<Currency, Currency, TradeType>
txHash: string | undefined txHash: string | undefined
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment