Commit e01f30c0 authored by lynn's avatar lynn Committed by GitHub

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
parent c60c028d
...@@ -45,6 +45,13 @@ function TextWithLoadingPlaceholder({ ...@@ -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({ export function AdvancedSwapDetails({
trade, trade,
allowedSlippage, allowedSlippage,
...@@ -59,7 +66,7 @@ export function AdvancedSwapDetails({ ...@@ -59,7 +66,7 @@ export function AdvancedSwapDetails({
if (!trade) return { expectedOutputAmount: undefined, priceImpact: undefined } if (!trade) return { expectedOutputAmount: undefined, priceImpact: undefined }
const expectedOutputAmount = trade.outputAmount const expectedOutputAmount = trade.outputAmount
const realizedLpFeePercent = computeRealizedLPFeePercent(trade) const realizedLpFeePercent = computeRealizedLPFeePercent(trade)
const priceImpact = trade.priceImpact.subtract(realizedLpFeePercent) const priceImpact = getPriceImpactPercent(realizedLpFeePercent, trade)
return { expectedOutputAmount, priceImpact } return { expectedOutputAmount, priceImpact }
}, [trade]) }, [trade])
......
...@@ -61,11 +61,13 @@ export default function ConfirmSwapModal({ ...@@ -61,11 +61,13 @@ export default function ConfirmSwapModal({
<SwapModalFooter <SwapModalFooter
onConfirm={onConfirm} onConfirm={onConfirm}
trade={trade} trade={trade}
txHash={txHash}
allowedSlippage={allowedSlippage}
disabledConfirm={showAcceptChanges} disabledConfirm={showAcceptChanges}
swapErrorMessage={swapErrorMessage} swapErrorMessage={swapErrorMessage}
/> />
) : null ) : null
}, [onConfirm, showAcceptChanges, swapErrorMessage, trade]) }, [onConfirm, showAcceptChanges, swapErrorMessage, trade, allowedSlippage, txHash])
// text to show while loading // text to show while loading
const pendingText = ( const pendingText = (
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Trade } from '@uniswap/router-sdk' import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core'
import { Currency, 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 { ReactNode } from 'react'
import { Text } from 'rebass' 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 { ButtonError } from '../Button'
import { AutoRow } from '../Row' import { AutoRow } from '../Row'
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 {
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({ export default function SwapModalFooter({
trade,
allowedSlippage,
txHash,
onConfirm, onConfirm,
swapErrorMessage, swapErrorMessage,
disabledConfirm, disabledConfirm,
}: { }: {
trade: Trade<Currency, Currency, TradeType> trade: InterfaceTrade<Currency, Currency, TradeType>
txHash: string | undefined
allowedSlippage: Percent
onConfirm: () => void onConfirm: () => void
swapErrorMessage: ReactNode | undefined swapErrorMessage: ReactNode | undefined
disabledConfirm: boolean 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 ( return (
<> <>
<AutoRow> <AutoRow>
<ButtonError <TraceEvent
onClick={onConfirm} events={[Event.onClick]}
disabled={disabledConfirm} element={ElementName.CONFIRM_SWAP_BUTTON}
style={{ margin: '10px 0 0 0' }} name={EventName.SWAP_SUBMITTED}
id="confirm-swap-or-send" properties={formatAnalyticsEventProperties({
trade,
txHash,
allowedSlippage,
transactionDeadlineSecondsSinceEpoch,
isAutoSlippage,
isAutoRouterApi: !clientSideRouter,
tokenInAmountUsd,
tokenOutAmountUsd,
lpFeePercent,
})}
> >
<Text fontSize={20} fontWeight={500}> <ButtonError
<Trans>Confirm Swap</Trans> onClick={onConfirm}
</Text> disabled={disabledConfirm}
</ButtonError> style={{ margin: '10px 0 0 0' }}
id={ElementName.CONFIRM_SWAP_BUTTON}
>
<Text fontSize={20} fontWeight={500}>
<Trans>Confirm Swap</Trans>
</Text>
</ButtonError>
</TraceEvent>
{swapErrorMessage ? <SwapCallbackError error={swapErrorMessage} /> : null} {swapErrorMessage ? <SwapCallbackError error={swapErrorMessage} /> : null}
</AutoRow> </AutoRow>
......
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