feat: widget analytics (#4869)
* chore: todos for analytics * example * another skeleton logging event * feat: onSwapApprove * feat: widget tracing * feat: better useTrace * feat: max * feat: switch * add trace amd remove onreviewswapclick * onExpandSwapDetails * feat: initial quote * add event properties for wrap * feat: update ack * SWAP_SIGNED * feat: submit * fix: wrap type * chore: tracing * move format fn to utils * fix: remove old background-color flash (#4890) remove old background-color * revert: add back phase0 bug fixes (#4888) * Revert "revert: removing phase0 bug fixes temporarily (#4886)" This reverts commit 06291a15a6af77b8493e14e2cb2c84cea5c10709. * use token amount * Revert "use token amount" This reverts commit f47c00358b29cfa9886bf4e490df4bf70b88e648. * dont render if empty * fix: upgrade pkg to eliminate compile error (#4898) * upgrade pkg * dedup * fix: Remove token selector flash of old ui (#4896) remove token selector flash of old view * fix: Web 1561 logging event for clicking on explore banner toast + WEB-1543 [Explore Banner] String should be sentence case (#4899) * explore banner changes * remove console log * oops * test: run tests on all PRs (#4905) * fix: use correct optimism icon in explore (#4893) * fix: click area should match button effect (#4887) * fix: update font-weight values to match spec (#4863) * fixes. working now verified on console. * fix: mobile tweaks (#4910) * update manifest theme colors to magenta * text spacing and right positioning on very small screens * feat: load token from query data (#4904) * fix: do not fetch balances cross-chain * build: updgrade widget * feat: cleanly load and switch chains from widget * fix: load token from query data * build: trigger checks * fix: do not override native token from query * fix: catch error on switch chain * refactor: useTokenFromActiveNetwork * refactor: defaultToken behavior clarification Co-authored-by: Zach Pomerantz <zzmp@uniswap.org> Co-authored-by: Jordan Frankfurt <jordanwfrankfurt@gmail.com> Co-authored-by: vignesh mohankumar <vignesh@vigneshmohankumar.com> Co-authored-by: cartcrom <39385577+cartcrom@users.noreply.github.com>
This commit is contained in:
parent
cdd5b66d1b
commit
a5c5567936
@ -20,6 +20,11 @@ export interface ITraceContext {
|
||||
|
||||
export const TraceContext = createContext<ITraceContext>({})
|
||||
|
||||
export function useTrace(trace?: ITraceContext): ITraceContext {
|
||||
const parentTrace = useContext(TraceContext)
|
||||
return useMemo(() => ({ ...parentTrace, ...trace }), [parentTrace, trace])
|
||||
}
|
||||
|
||||
type TraceProps = {
|
||||
shouldLogImpression?: boolean // whether to log impression on mount
|
||||
name?: EventName
|
||||
@ -31,15 +36,24 @@ type TraceProps = {
|
||||
* and propagates the context to child traces.
|
||||
*/
|
||||
export const Trace = memo(
|
||||
({ shouldLogImpression, name, children, page, section, element, properties }: PropsWithChildren<TraceProps>) => {
|
||||
const parentTrace = useContext(TraceContext)
|
||||
({
|
||||
shouldLogImpression,
|
||||
name,
|
||||
children,
|
||||
page,
|
||||
section,
|
||||
modal,
|
||||
element,
|
||||
properties,
|
||||
}: PropsWithChildren<TraceProps>) => {
|
||||
const parentTrace = useTrace()
|
||||
|
||||
const combinedProps = useMemo(
|
||||
() => ({
|
||||
...parentTrace,
|
||||
...Object.fromEntries(Object.entries({ page, section, element }).filter(([_, v]) => v !== undefined)),
|
||||
...Object.fromEntries(Object.entries({ page, section, modal, element }).filter(([_, v]) => v !== undefined)),
|
||||
}),
|
||||
[element, parentTrace, page, section]
|
||||
[element, parentTrace, page, modal, section]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -89,6 +89,7 @@ export enum PageName {
|
||||
export enum SectionName {
|
||||
CURRENCY_INPUT_PANEL = 'swap-currency-input',
|
||||
CURRENCY_OUTPUT_PANEL = 'swap-currency-output',
|
||||
WIDGET = 'widget',
|
||||
// alphabetize additional section names.
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,16 @@
|
||||
import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core'
|
||||
import { Trade } from '@uniswap/router-sdk'
|
||||
import { Currency, CurrencyAmount, Percent, Price, Token, TradeType } from '@uniswap/sdk-core'
|
||||
import { NATIVE_CHAIN_ID } from 'constants/tokens'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import { computeRealizedPriceImpact } from 'utils/prices'
|
||||
|
||||
export const getDurationUntilTimestampSeconds = (futureTimestampInSecondsSinceEpoch?: number): number | undefined => {
|
||||
if (!futureTimestampInSecondsSinceEpoch) return undefined
|
||||
return futureTimestampInSecondsSinceEpoch - new Date().getTime() / 1000
|
||||
}
|
||||
|
||||
export const getDurationFromDateMilliseconds = (start: Date): number => {
|
||||
export const getDurationFromDateMilliseconds = (start?: Date): number | undefined => {
|
||||
if (!start) return undefined
|
||||
return new Date().getTime() - start.getTime()
|
||||
}
|
||||
|
||||
@ -20,3 +24,57 @@ export const getTokenAddress = (currency: Currency) => (currency.isNative ? NATI
|
||||
export const formatPercentInBasisPointsNumber = (percent: Percent): number => parseFloat(percent.toFixed(2)) * 100
|
||||
|
||||
export const formatPercentNumber = (percent: Percent): number => parseFloat(percent.toFixed(2))
|
||||
|
||||
export const getPriceUpdateBasisPoints = (
|
||||
prevPrice: Price<Currency, Currency>,
|
||||
newPrice: Price<Currency, Currency>
|
||||
): number => {
|
||||
const changeFraction = newPrice.subtract(prevPrice).divide(prevPrice)
|
||||
const changePercentage = new Percent(changeFraction.numerator, changeFraction.denominator)
|
||||
return formatPercentInBasisPointsNumber(changePercentage)
|
||||
}
|
||||
|
||||
export const formatSwapSignedAnalyticsEventProperties = ({
|
||||
trade,
|
||||
txHash,
|
||||
}: {
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType> | Trade<Currency, Currency, TradeType>
|
||||
txHash: string
|
||||
}) => ({
|
||||
transaction_hash: txHash,
|
||||
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),
|
||||
token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals),
|
||||
price_impact_basis_points: formatPercentInBasisPointsNumber(computeRealizedPriceImpact(trade)),
|
||||
chain_id:
|
||||
trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId
|
||||
? trade.inputAmount.currency.chainId
|
||||
: undefined,
|
||||
})
|
||||
|
||||
export const formatSwapQuoteReceivedEventProperties = (
|
||||
trade: Trade<Currency, Currency, TradeType>,
|
||||
gasUseEstimateUSD?: CurrencyAmount<Token>,
|
||||
fetchingSwapQuoteStartTime?: Date
|
||||
) => {
|
||||
return {
|
||||
token_in_symbol: trade.inputAmount.currency.symbol,
|
||||
token_out_symbol: trade.outputAmount.currency.symbol,
|
||||
token_in_address: getTokenAddress(trade.inputAmount.currency),
|
||||
token_out_address: getTokenAddress(trade.outputAmount.currency),
|
||||
price_impact_basis_points: trade ? formatPercentInBasisPointsNumber(computeRealizedPriceImpact(trade)) : undefined,
|
||||
estimated_network_fee_usd: gasUseEstimateUSD ? formatToDecimal(gasUseEstimateUSD, 2) : undefined,
|
||||
chain_id:
|
||||
trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId
|
||||
? trade.inputAmount.currency.chainId
|
||||
: undefined,
|
||||
token_in_amount: formatToDecimal(trade.inputAmount, trade.inputAmount.currency.decimals),
|
||||
token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals),
|
||||
quote_latency_milliseconds: fetchingSwapQuoteStartTime
|
||||
? getDurationFromDateMilliseconds(fetchingSwapQuoteStartTime)
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
@ -2,19 +2,31 @@
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import '@uniswap/widgets/dist/fonts.css'
|
||||
|
||||
import { Trade } from '@uniswap/router-sdk'
|
||||
import { Currency, TradeType } from '@uniswap/sdk-core'
|
||||
import {
|
||||
AddEthereumChainParameter,
|
||||
Currency,
|
||||
EMPTY_TOKEN_LIST,
|
||||
OnReviewSwapClick,
|
||||
SwapWidget,
|
||||
SwapWidgetSkeleton,
|
||||
} from '@uniswap/widgets'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { sendAnalyticsEvent } from 'analytics'
|
||||
import { EventName, SectionName } from 'analytics/constants'
|
||||
import { SWAP_PRICE_UPDATE_USER_RESPONSE } from 'analytics/constants'
|
||||
import { useTrace } from 'analytics/Trace'
|
||||
import {
|
||||
formatPercentInBasisPointsNumber,
|
||||
formatToDecimal,
|
||||
getPriceUpdateBasisPoints,
|
||||
getTokenAddress,
|
||||
} from 'analytics/utils'
|
||||
import { useActiveLocale } from 'hooks/useActiveLocale'
|
||||
import { useCallback } from 'react'
|
||||
import { useIsDarkMode } from 'state/user/hooks'
|
||||
import { DARK_THEME, LIGHT_THEME } from 'theme/widget'
|
||||
import { computeRealizedPriceImpact } from 'utils/prices'
|
||||
import { switchChain } from 'utils/switchChain'
|
||||
|
||||
import { useSyncWidgetInputs } from './inputs'
|
||||
@ -39,6 +51,71 @@ export default function Widget({ defaultToken, onReviewSwapClick }: WidgetProps)
|
||||
const { settings } = useSyncWidgetSettings()
|
||||
const { transactions } = useSyncWidgetTransactions()
|
||||
|
||||
const trace = useTrace({ section: SectionName.WIDGET })
|
||||
|
||||
// TODO(lynnshaoyu): add back onInitialSwapQuote logging once widget side logic is fixed
|
||||
// in onInitialSwapQuote handler.
|
||||
|
||||
const onApproveToken = useCallback(() => {
|
||||
const input = inputs.value.INPUT
|
||||
if (!input) return
|
||||
const eventProperties = {
|
||||
chain_id: input.chainId,
|
||||
token_symbol: input.symbol,
|
||||
token_address: getTokenAddress(input),
|
||||
...trace,
|
||||
}
|
||||
sendAnalyticsEvent(EventName.APPROVE_TOKEN_TXN_SUBMITTED, eventProperties)
|
||||
}, [inputs.value.INPUT, trace])
|
||||
|
||||
const onExpandSwapDetails = useCallback(() => {
|
||||
sendAnalyticsEvent(EventName.SWAP_DETAILS_EXPANDED, { ...trace })
|
||||
}, [trace])
|
||||
|
||||
const onSwapPriceUpdateAck = useCallback(
|
||||
(stale: Trade<Currency, Currency, TradeType>, update: Trade<Currency, Currency, TradeType>) => {
|
||||
const eventProperties = {
|
||||
chain_id: update.inputAmount.currency.chainId,
|
||||
response: SWAP_PRICE_UPDATE_USER_RESPONSE.ACCEPTED,
|
||||
token_in_symbol: update.inputAmount.currency.symbol,
|
||||
token_out_symbol: update.outputAmount.currency.symbol,
|
||||
price_update_basis_points: getPriceUpdateBasisPoints(stale.executionPrice, update.executionPrice),
|
||||
...trace,
|
||||
}
|
||||
sendAnalyticsEvent(EventName.SWAP_PRICE_UPDATE_ACKNOWLEDGED, eventProperties)
|
||||
},
|
||||
[trace]
|
||||
)
|
||||
|
||||
const onSubmitSwapClick = useCallback(
|
||||
(trade: Trade<Currency, Currency, TradeType>) => {
|
||||
const eventProperties = {
|
||||
// TODO(1416): Include undefined values.
|
||||
estimated_network_fee_usd: undefined,
|
||||
transaction_deadline_seconds: 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: formatToDecimal(trade.inputAmount, trade.inputAmount.currency.decimals),
|
||||
token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals),
|
||||
token_in_amount_usd: undefined,
|
||||
token_out_amount_usd: undefined,
|
||||
price_impact_basis_points: formatPercentInBasisPointsNumber(computeRealizedPriceImpact(trade)),
|
||||
allowed_slippage_basis_points: undefined,
|
||||
is_auto_router_api: undefined,
|
||||
is_auto_slippage: undefined,
|
||||
chain_id: trade.inputAmount.currency.chainId,
|
||||
// duration should be getDurationFromDateMilliseconds(initialQuoteDate) once initialQuoteDate
|
||||
// is made available from TODO above for onInitialSwapQuote logging.
|
||||
duration_from_first_quote_to_swap_submission_milliseconds: undefined,
|
||||
swap_quote_block_number: undefined,
|
||||
...trace,
|
||||
}
|
||||
sendAnalyticsEvent(EventName.SWAP_SUBMITTED_BUTTON_CLICKED, eventProperties)
|
||||
},
|
||||
[trace]
|
||||
)
|
||||
const onSwitchChain = useCallback(
|
||||
// TODO: Widget should not break if this rejects - upstream the catch to ignore it.
|
||||
({ chainId }: AddEthereumChainParameter) => switchChain(connector, Number(chainId)).catch(() => undefined),
|
||||
@ -58,7 +135,6 @@ export default function Widget({ defaultToken, onReviewSwapClick }: WidgetProps)
|
||||
width={WIDGET_WIDTH}
|
||||
locale={locale}
|
||||
theme={theme}
|
||||
onReviewSwapClick={onReviewSwapClick}
|
||||
// defaultChainId is excluded - it is always inferred from the passed provider
|
||||
provider={provider}
|
||||
onSwitchChain={onSwitchChain}
|
||||
@ -66,6 +142,11 @@ export default function Widget({ defaultToken, onReviewSwapClick }: WidgetProps)
|
||||
{...inputs}
|
||||
{...settings}
|
||||
{...transactions}
|
||||
onExpandSwapDetails={onExpandSwapDetails}
|
||||
onReviewSwapClick={onReviewSwapClick}
|
||||
onSubmitSwapClick={onSubmitSwapClick}
|
||||
onSwapApprove={onApproveToken}
|
||||
onSwapPriceUpdateAck={onSwapPriceUpdateAck}
|
||||
/>
|
||||
{tokenSelector}
|
||||
</>
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { Currency, Field, SwapController, SwapEventHandlers, TradeType } from '@uniswap/widgets'
|
||||
import { sendAnalyticsEvent } from 'analytics'
|
||||
import { EventName, SectionName } from 'analytics/constants'
|
||||
import { useTrace } from 'analytics/Trace'
|
||||
import CurrencySearchModal from 'components/SearchModal/CurrencySearchModal'
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
@ -9,12 +12,20 @@ const EMPTY_AMOUNT = ''
|
||||
* Treats the Widget as a controlled component, using the app's own token selector for selection.
|
||||
*/
|
||||
export function useSyncWidgetInputs(defaultToken?: Currency) {
|
||||
const trace = useTrace({ section: SectionName.WIDGET })
|
||||
|
||||
const [type, setType] = useState(TradeType.EXACT_INPUT)
|
||||
const [amount, setAmount] = useState(EMPTY_AMOUNT)
|
||||
const onAmountChange = useCallback((field: Field, amount: string) => {
|
||||
setType(toTradeType(field))
|
||||
setAmount(amount)
|
||||
}, [])
|
||||
const onAmountChange = useCallback(
|
||||
(field: Field, amount: string, origin?: 'max') => {
|
||||
if (origin === 'max') {
|
||||
sendAnalyticsEvent(EventName.SWAP_MAX_TOKEN_AMOUNT_SELECTED, { ...trace })
|
||||
}
|
||||
setType(toTradeType(field))
|
||||
setAmount(amount)
|
||||
},
|
||||
[trace]
|
||||
)
|
||||
|
||||
const [tokens, setTokens] = useState<{ [Field.INPUT]?: Currency; [Field.OUTPUT]?: Currency }>({
|
||||
[Field.OUTPUT]: defaultToken,
|
||||
@ -30,12 +41,13 @@ export function useSyncWidgetInputs(defaultToken?: Currency) {
|
||||
}, [defaultToken])
|
||||
|
||||
const onSwitchTokens = useCallback(() => {
|
||||
sendAnalyticsEvent(EventName.SWAP_TOKENS_REVERSED, { ...trace })
|
||||
setType((type) => invertTradeType(type))
|
||||
setTokens((tokens) => ({
|
||||
[Field.INPUT]: tokens[Field.OUTPUT],
|
||||
[Field.OUTPUT]: tokens[Field.INPUT],
|
||||
}))
|
||||
}, [])
|
||||
}, [trace])
|
||||
|
||||
const [selectingField, setSelectingField] = useState<Field>()
|
||||
const otherField = useMemo(() => (selectingField === Field.INPUT ? Field.OUTPUT : Field.INPUT), [selectingField])
|
||||
|
@ -6,6 +6,12 @@ import {
|
||||
TransactionType as WidgetTransactionType,
|
||||
} from '@uniswap/widgets'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { sendAnalyticsEvent } from 'analytics'
|
||||
import { EventName, SectionName } from 'analytics/constants'
|
||||
import { useTrace } from 'analytics/Trace'
|
||||
import { formatToDecimal, getTokenAddress } from 'analytics/utils'
|
||||
import { formatSwapSignedAnalyticsEventProperties } from 'analytics/utils'
|
||||
import { WrapType } from 'hooks/useWrapCallback'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTransactionAdder } from 'state/transactions/hooks'
|
||||
import {
|
||||
@ -18,6 +24,8 @@ import { currencyId } from 'utils/currencyId'
|
||||
|
||||
/** Integrates the Widget's transactions, showing the widget's transactions in the app. */
|
||||
export function useSyncWidgetTransactions() {
|
||||
const trace = useTrace({ section: SectionName.WIDGET })
|
||||
|
||||
const { chainId } = useWeb3React()
|
||||
const addTransaction = useTransactionAdder()
|
||||
|
||||
@ -28,8 +36,23 @@ export function useSyncWidgetTransactions() {
|
||||
if (!type || !response) {
|
||||
return
|
||||
} else if (type === WidgetTransactionType.WRAP || type === WidgetTransactionType.UNWRAP) {
|
||||
const { amount } = transaction.info
|
||||
const { type, amount: transactionAmount } = transaction.info
|
||||
|
||||
const eventProperties = {
|
||||
// get this info from widget handlers
|
||||
token_in_address: getTokenAddress(transactionAmount.currency),
|
||||
token_out_address: getTokenAddress(transactionAmount.currency.wrapped),
|
||||
token_in_symbol: transactionAmount.currency.symbol,
|
||||
token_out_symbol: transactionAmount.currency.wrapped.symbol,
|
||||
chain_id: transactionAmount.currency.chainId,
|
||||
amount: transactionAmount
|
||||
? formatToDecimal(transactionAmount, transactionAmount?.currency.decimals)
|
||||
: undefined,
|
||||
type: type === WidgetTransactionType.WRAP ? WrapType.WRAP : WrapType.UNWRAP,
|
||||
...trace,
|
||||
}
|
||||
sendAnalyticsEvent(EventName.WRAP_TOKEN_TXN_SUBMITTED, eventProperties)
|
||||
const { amount } = transaction.info
|
||||
addTransaction(response, {
|
||||
type: AppTransactionType.WRAP,
|
||||
unwrapped: type === WidgetTransactionType.UNWRAP,
|
||||
@ -38,6 +61,15 @@ export function useSyncWidgetTransactions() {
|
||||
} as WrapTransactionInfo)
|
||||
} else if (type === WidgetTransactionType.SWAP) {
|
||||
const { slippageTolerance, trade, tradeType } = transaction.info
|
||||
|
||||
const eventProperties = {
|
||||
...formatSwapSignedAnalyticsEventProperties({
|
||||
trade,
|
||||
txHash: transaction.receipt?.transactionHash ?? '',
|
||||
}),
|
||||
...trace,
|
||||
}
|
||||
sendAnalyticsEvent(EventName.SWAP_SIGNED, eventProperties)
|
||||
const baseTxInfo = {
|
||||
type: AppTransactionType.SWAP,
|
||||
tradeType,
|
||||
@ -61,7 +93,7 @@ export function useSyncWidgetTransactions() {
|
||||
}
|
||||
}
|
||||
},
|
||||
[addTransaction, chainId]
|
||||
[addTransaction, chainId, trace]
|
||||
)
|
||||
|
||||
const txHandlers: TransactionEventHandlers = useMemo(() => ({ onTxSubmit }), [onTxSubmit])
|
||||
|
@ -5,10 +5,9 @@ import { sendAnalyticsEvent } from 'analytics'
|
||||
import { ModalName } from 'analytics/constants'
|
||||
import { EventName } from 'analytics/constants'
|
||||
import { Trace } from 'analytics/Trace'
|
||||
import { formatPercentInBasisPointsNumber, formatToDecimal, getTokenAddress } from 'analytics/utils'
|
||||
import { formatSwapSignedAnalyticsEventProperties } from 'analytics/utils'
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { InterfaceTrade } from 'state/routing/types'
|
||||
import { computeRealizedPriceImpact } from 'utils/prices'
|
||||
import { tradeMeaningfullyDiffers } from 'utils/tradeMeaningFullyDiffer'
|
||||
|
||||
import TransactionConfirmationModal, {
|
||||
@ -18,27 +17,6 @@ import TransactionConfirmationModal, {
|
||||
import SwapModalFooter from './SwapModalFooter'
|
||||
import SwapModalHeader from './SwapModalHeader'
|
||||
|
||||
const formatAnalyticsEventProperties = ({
|
||||
trade,
|
||||
txHash,
|
||||
}: {
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType>
|
||||
txHash: string
|
||||
}) => ({
|
||||
transaction_hash: txHash,
|
||||
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),
|
||||
token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals),
|
||||
price_impact_basis_points: formatPercentInBasisPointsNumber(computeRealizedPriceImpact(trade)),
|
||||
chain_id:
|
||||
trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId
|
||||
? trade.inputAmount.currency.chainId
|
||||
: undefined,
|
||||
})
|
||||
|
||||
export default function ConfirmSwapModal({
|
||||
trade,
|
||||
originalTrade,
|
||||
@ -149,7 +127,7 @@ export default function ConfirmSwapModal({
|
||||
|
||||
useEffect(() => {
|
||||
if (!attemptingTxn && isOpen && txHash && trade && txHash !== lastTxnHashLogged) {
|
||||
sendAnalyticsEvent(EventName.SWAP_SIGNED, formatAnalyticsEventProperties({ trade, txHash }))
|
||||
sendAnalyticsEvent(EventName.SWAP_SIGNED, formatSwapSignedAnalyticsEventProperties({ trade, txHash }))
|
||||
setLastTxnHashLogged(txHash)
|
||||
}
|
||||
}, [attemptingTxn, isOpen, txHash, trade, lastTxnHashLogged])
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { Price } from '@uniswap/sdk-core'
|
||||
import { sendAnalyticsEvent } from 'analytics'
|
||||
import { EventName, SWAP_PRICE_UPDATE_USER_RESPONSE } from 'analytics/constants'
|
||||
import { formatPercentInBasisPointsNumber } from 'analytics/utils'
|
||||
import { getPriceUpdateBasisPoints } from 'analytics/utils'
|
||||
import { RedesignVariant, useRedesignFlag } from 'featureFlags/flags/redesign'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { AlertTriangle, ArrowDown } from 'react-feather'
|
||||
@ -58,15 +57,6 @@ const formatAnalyticsEventProperties = (
|
||||
price_update_basis_points: priceUpdate,
|
||||
})
|
||||
|
||||
const getPriceUpdateBasisPoints = (
|
||||
prevPrice: Price<Currency, Currency>,
|
||||
newPrice: Price<Currency, Currency>
|
||||
): number => {
|
||||
const changeFraction = newPrice.subtract(prevPrice).divide(prevPrice)
|
||||
const changePercentage = new Percent(changeFraction.numerator, changeFraction.denominator)
|
||||
return formatPercentInBasisPointsNumber(changePercentage)
|
||||
}
|
||||
|
||||
export default function SwapModalHeader({
|
||||
trade,
|
||||
shouldLogModalCloseEvent,
|
||||
|
@ -6,12 +6,7 @@ import { sendAnalyticsEvent } from 'analytics'
|
||||
import { ElementName, Event, EventName, PageName, SectionName } from 'analytics/constants'
|
||||
import { Trace } from 'analytics/Trace'
|
||||
import { TraceEvent } from 'analytics/TraceEvent'
|
||||
import {
|
||||
formatPercentInBasisPointsNumber,
|
||||
formatToDecimal,
|
||||
getDurationFromDateMilliseconds,
|
||||
getTokenAddress,
|
||||
} from 'analytics/utils'
|
||||
import { formatSwapQuoteReceivedEventProperties } from 'analytics/utils'
|
||||
import { sendEvent } from 'components/analytics'
|
||||
import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert'
|
||||
import PriceImpactWarning from 'components/swap/PriceImpactWarning'
|
||||
@ -153,29 +148,6 @@ function largerPercentValue(a?: Percent, b?: Percent) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const formatSwapQuoteReceivedEventProperties = (
|
||||
trade: InterfaceTrade<Currency, Currency, TradeType>,
|
||||
fetchingSwapQuoteStartTime: Date | undefined
|
||||
) => {
|
||||
return {
|
||||
token_in_symbol: trade.inputAmount.currency.symbol,
|
||||
token_out_symbol: trade.outputAmount.currency.symbol,
|
||||
token_in_address: getTokenAddress(trade.inputAmount.currency),
|
||||
token_out_address: getTokenAddress(trade.outputAmount.currency),
|
||||
price_impact_basis_points: trade ? formatPercentInBasisPointsNumber(computeRealizedPriceImpact(trade)) : 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: formatToDecimal(trade.inputAmount, trade.inputAmount.currency.decimals),
|
||||
token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals),
|
||||
quote_latency_milliseconds: fetchingSwapQuoteStartTime
|
||||
? getDurationFromDateMilliseconds(fetchingSwapQuoteStartTime)
|
||||
: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
const TRADE_STRING = 'SwapRouter'
|
||||
|
||||
export default function Swap() {
|
||||
@ -510,7 +482,7 @@ export default function Swap() {
|
||||
// Log swap quote.
|
||||
sendAnalyticsEvent(
|
||||
EventName.SWAP_QUOTE_RECEIVED,
|
||||
formatSwapQuoteReceivedEventProperties(trade, fetchingSwapQuoteStartTime)
|
||||
formatSwapQuoteReceivedEventProperties(trade, trade.gasUseEstimateUSD ?? undefined, 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.
|
||||
|
Loading…
Reference in New Issue
Block a user