feat: Web 214 implement the main submit swap event (#4061)

* 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

* create helper function getPriceImpactPercentageNumber

* 4 decimal points for percentages

* change percentage to basis points units
This commit is contained in:
lynn 2022-07-21 17:44:34 -04:00 committed by GitHub
parent c60c028dbe
commit e01f30c0b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 14 deletions

@ -45,6 +45,13 @@ function TextWithLoadingPlaceholder({
)
}
export function getPriceImpactPercent(
lpFeePercent: Percent,
trade: InterfaceTrade<Currency, Currency, TradeType>
): Percent {
return trade.priceImpact.subtract(lpFeePercent)
}
export function AdvancedSwapDetails({
trade,
allowedSlippage,
@ -59,7 +66,7 @@ export function AdvancedSwapDetails({
if (!trade) return { expectedOutputAmount: undefined, priceImpact: undefined }
const expectedOutputAmount = trade.outputAmount
const realizedLpFeePercent = computeRealizedLPFeePercent(trade)
const priceImpact = trade.priceImpact.subtract(realizedLpFeePercent)
const priceImpact = getPriceImpactPercent(realizedLpFeePercent, trade)
return { expectedOutputAmount, priceImpact }
}, [trade])

@ -61,11 +61,13 @@ export default function ConfirmSwapModal({
<SwapModalFooter
onConfirm={onConfirm}
trade={trade}
txHash={txHash}
allowedSlippage={allowedSlippage}
disabledConfirm={showAcceptChanges}
swapErrorMessage={swapErrorMessage}
/>
) : null
}, [onConfirm, showAcceptChanges, swapErrorMessage, trade])
}, [onConfirm, showAcceptChanges, swapErrorMessage, trade, allowedSlippage, txHash])
// text to show while loading
const pendingText = (

@ -1,36 +1,132 @@
import { Trans } from '@lingui/macro'
import { Trade } from '@uniswap/router-sdk'
import { Currency, TradeType } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core'
import { ElementName, EventName } from 'components/AmplitudeAnalytics/constants'
import { Event } from 'components/AmplitudeAnalytics/constants'
import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent'
import { useStablecoinValue } from 'hooks/useStablecoinPrice'
import useTransactionDeadline from 'hooks/useTransactionDeadline'
import { ReactNode } from 'react'
import { Text } from 'rebass'
import { InterfaceTrade } from 'state/routing/types'
import { useClientSideRouter, useUserSlippageTolerance } from 'state/user/hooks'
import { computeRealizedLPFeePercent } from 'utils/prices'
import { ButtonError } from '../Button'
import { AutoRow } from '../Row'
import { getPriceImpactPercent } from './AdvancedSwapDetails'
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 {
trade: InterfaceTrade<Currency, Currency, TradeType>
txHash: string | undefined
allowedSlippage: Percent
transactionDeadlineSecondsSinceEpoch: number | undefined
isAutoSlippage: boolean
isAutoRouterApi: boolean
tokenInAmountUsd: string | undefined
tokenOutAmountUsd: string | undefined
lpFeePercent: Percent
}
const formatAnalyticsEventProperties = ({
trade,
txHash,
allowedSlippage,
transactionDeadlineSecondsSinceEpoch,
isAutoSlippage,
isAutoRouterApi,
tokenInAmountUsd,
tokenOutAmountUsd,
lpFeePercent,
}: AnalyticsEventProps) => ({
estimated_network_fee_usd: trade.gasUseEstimateUSD
? getNumberFormattedToDecimalPlace(trade.gasUseEstimateUSD, 2)
: undefined,
transaction_hash: txHash,
transaction_deadline_seconds: getDurationTillTimestampSinceEpoch(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_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),
price_impact_basis_points: formatPercentInBasisPointsNumber(getPriceImpactPercent(lpFeePercent, trade)),
allowed_slippage_basis_points: formatPercentInBasisPointsNumber(allowedSlippage),
is_auto_router_api: isAutoRouterApi,
is_auto_slippage: isAutoSlippage,
chain_id:
trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId
? trade.inputAmount.currency.chainId
: undefined,
// TODO(lynnshaoyu): implement duration_from_first_quote_to_swap_submission_seconds
})
export default function SwapModalFooter({
trade,
allowedSlippage,
txHash,
onConfirm,
swapErrorMessage,
disabledConfirm,
}: {
trade: Trade<Currency, Currency, TradeType>
trade: InterfaceTrade<Currency, Currency, TradeType>
txHash: string | undefined
allowedSlippage: Percent
onConfirm: () => void
swapErrorMessage: ReactNode | undefined
disabledConfirm: boolean
}) {
const transactionDeadlineSecondsSinceEpoch = useTransactionDeadline()?.toNumber() // in seconds since epoch
const isAutoSlippage = useUserSlippageTolerance() === 'auto'
const [clientSideRouter] = useClientSideRouter()
const tokenInAmountUsd = useStablecoinValue(trade.inputAmount)?.toFixed(2)
const tokenOutAmountUsd = useStablecoinValue(trade.outputAmount)?.toFixed(2)
const lpFeePercent = computeRealizedLPFeePercent(trade)
return (
<>
<AutoRow>
<TraceEvent
events={[Event.onClick]}
element={ElementName.CONFIRM_SWAP_BUTTON}
name={EventName.SWAP_SUBMITTED}
properties={formatAnalyticsEventProperties({
trade,
txHash,
allowedSlippage,
transactionDeadlineSecondsSinceEpoch,
isAutoSlippage,
isAutoRouterApi: !clientSideRouter,
tokenInAmountUsd,
tokenOutAmountUsd,
lpFeePercent,
})}
>
<ButtonError
onClick={onConfirm}
disabled={disabledConfirm}
style={{ margin: '10px 0 0 0' }}
id="confirm-swap-or-send"
id={ElementName.CONFIRM_SWAP_BUTTON}
>
<Text fontSize={20} fontWeight={500}>
<Trans>Confirm Swap</Trans>
</Text>
</ButtonError>
</TraceEvent>
{swapErrorMessage ? <SwapCallbackError error={swapErrorMessage} /> : null}
</AutoRow>