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

feat: new swap events and properties in taxonomy (#4204)

* init commit

* remove absolute value in date calc

* all the events are now logged properly plus changed native token address to NATIVE

* add documentation line

* remove unnecessary prop

* init

* add approve token event

* fix build

* add route event properties

* fix build

* respond to vm comments

* respond to vm comments

* remove routes properties
parent 7a78a7b4
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
* and logged. * and logged.
*/ */
export enum EventName { export enum EventName {
APPROVE_TOKEN_TXN_SUBMITTED = 'Approve Token Transaction Submitted',
CONNECT_WALLET_BUTTON_CLICKED = 'Connect Wallet Button Clicked', CONNECT_WALLET_BUTTON_CLICKED = 'Connect Wallet Button Clicked',
PAGE_VIEWED = 'Page Viewed', PAGE_VIEWED = 'Page Viewed',
SWAP_AUTOROUTER_VISUALIZATION_EXPANDED = 'Swap Autorouter Visualization Expanded', SWAP_AUTOROUTER_VISUALIZATION_EXPANDED = 'Swap Autorouter Visualization Expanded',
...@@ -20,6 +21,7 @@ export enum EventName { ...@@ -20,6 +21,7 @@ export enum EventName {
TOKEN_SELECTOR_OPENED = 'Token Selector Opened', TOKEN_SELECTOR_OPENED = 'Token Selector Opened',
WALLET_CONNECT_TXN_COMPLETED = 'Wallet Connect Transaction Completed', WALLET_CONNECT_TXN_COMPLETED = 'Wallet Connect Transaction Completed',
WALLET_SELECTED = 'Wallet Selected', WALLET_SELECTED = 'Wallet Selected',
WRAP_TOKEN_TXN_SUBMITTED = 'Wrap Token Transaction Submitted',
// alphabetize additional event names. // alphabetize additional event names.
} }
...@@ -81,6 +83,7 @@ export const enum ModalName { ...@@ -81,6 +83,7 @@ export const enum ModalName {
* Use to identify low-level components given a TraceContext * Use to identify low-level components given a TraceContext
*/ */
export const enum ElementName { export const enum ElementName {
APPROVE_TOKEN_BUTTON = 'approve-token-button',
AUTOROUTER_VISUALIZATION_ROW = 'expandable-autorouter-visualization-row', AUTOROUTER_VISUALIZATION_ROW = 'expandable-autorouter-visualization-row',
COMMON_BASES_CURRENCY_BUTTON = 'common-bases-currency-button', COMMON_BASES_CURRENCY_BUTTON = 'common-bases-currency-button',
CONFIRM_SWAP_BUTTON = 'confirm-swap-or-send', CONFIRM_SWAP_BUTTON = 'confirm-swap-or-send',
...@@ -93,6 +96,7 @@ export const enum ElementName { ...@@ -93,6 +96,7 @@ export const enum ElementName {
SWAP_TOKENS_REVERSE_ARROW_BUTTON = 'swap-tokens-reverse-arrow-button', SWAP_TOKENS_REVERSE_ARROW_BUTTON = 'swap-tokens-reverse-arrow-button',
TOKEN_SELECTOR_ROW = 'token-selector-row', TOKEN_SELECTOR_ROW = 'token-selector-row',
WALLET_TYPE_OPTION = 'wallet-type-option', WALLET_TYPE_OPTION = 'wallet-type-option',
WRAP_TOKEN_BUTTON = 'wrap-token-button',
// alphabetize additional element names. // alphabetize additional element names.
} }
......
...@@ -19,3 +19,5 @@ export const formatToDecimal = ( ...@@ -19,3 +19,5 @@ export const formatToDecimal = (
export const getTokenAddress = (currency: Currency) => (currency.isNative ? NATIVE_CHAIN_ID : currency.address) export const getTokenAddress = (currency: Currency) => (currency.isNative ? NATIVE_CHAIN_ID : currency.address)
export const formatPercentInBasisPointsNumber = (percent: Percent): number => parseFloat(percent.toFixed(2)) * 100 export const formatPercentInBasisPointsNumber = (percent: Percent): number => parseFloat(percent.toFixed(2)) * 100
export const formatPercentNumber = (percent: Percent): number => parseFloat(percent.toFixed(2))
...@@ -85,6 +85,37 @@ export function getIsValidSwapQuote( ...@@ -85,6 +85,37 @@ export function getIsValidSwapQuote(
return !!swapInputError && !!trade && (tradeState === TradeState.VALID || tradeState === TradeState.SYNCING) return !!swapInputError && !!trade && (tradeState === TradeState.VALID || tradeState === TradeState.SYNCING)
} }
const formatApproveTokenTxnSubmittedEventProperties = (
approvalOptimizedTrade:
| Trade<Currency, Currency, TradeType>
| V2Trade<Currency, Currency, TradeType>
| V3Trade<Currency, Currency, TradeType>
| undefined
) => {
if (!approvalOptimizedTrade) return {}
return {
chain_id: approvalOptimizedTrade.inputAmount.currency.chainId,
token_symbol: approvalOptimizedTrade.inputAmount.currency.symbol,
token_address: getTokenAddress(approvalOptimizedTrade.inputAmount.currency),
}
}
const formatWrapTokenTxnSubmittedEventProperties = (
inputCurrency: Currency | null | undefined,
outputCurrency: Currency | null | undefined,
parsedAmount: CurrencyAmount<Currency> | undefined
) => {
if (!inputCurrency || !outputCurrency || !parsedAmount) return {}
return {
token_in_address: getTokenAddress(inputCurrency),
token_out_address: getTokenAddress(outputCurrency),
token_in_symbol: inputCurrency.symbol,
token_out_symbol: outputCurrency.symbol,
chain_id: inputCurrency.chainId,
amount: parsedAmount ? formatToDecimal(parsedAmount, parsedAmount?.currency.decimals) : undefined,
}
}
function largerPercentValue(a?: Percent, b?: Percent) { function largerPercentValue(a?: Percent, b?: Percent) {
if (a && b) { if (a && b) {
return a.greaterThan(b) ? a : b return a.greaterThan(b) ? a : b
...@@ -96,7 +127,7 @@ function largerPercentValue(a?: Percent, b?: Percent) { ...@@ -96,7 +127,7 @@ function largerPercentValue(a?: Percent, b?: Percent) {
return undefined return undefined
} }
const formatAnalyticsEventProperties = ( const formatSwapQuoteReceivedEventProperties = (
trade: InterfaceTrade<Currency, Currency, TradeType>, trade: InterfaceTrade<Currency, Currency, TradeType>,
fetchingSwapQuoteStartTime: Date | undefined fetchingSwapQuoteStartTime: Date | undefined
) => { ) => {
...@@ -462,7 +493,7 @@ export default function Swap() { ...@@ -462,7 +493,7 @@ export default function Swap() {
// Log swap quote. // Log swap quote.
sendAnalyticsEvent( sendAnalyticsEvent(
EventName.SWAP_QUOTE_RECEIVED, EventName.SWAP_QUOTE_RECEIVED,
formatAnalyticsEventProperties(trade, fetchingSwapQuoteStartTime) formatSwapQuoteReceivedEventProperties(trade, fetchingSwapQuoteStartTime)
) )
// Latest swap quote has just been logged, so we don't need to log the current trade anymore // 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. // unless user inputs change again and a new trade is in the process of being generated.
...@@ -484,6 +515,9 @@ export default function Swap() { ...@@ -484,6 +515,9 @@ export default function Swap() {
setSwapQuoteReceivedDate, setSwapQuoteReceivedDate,
]) ])
const approveTokenButtonDisabled =
approvalState !== ApprovalState.NOT_APPROVED || approvalSubmitted || signatureState === UseERC20PermitState.SIGNED
return ( return (
<Trace page={PageName.SWAP_PAGE} shouldLogImpression> <Trace page={PageName.SWAP_PAGE} shouldLogImpression>
<> <>
...@@ -619,15 +653,27 @@ export default function Swap() { ...@@ -619,15 +653,27 @@ export default function Swap() {
</ButtonLight> </ButtonLight>
</TraceEvent> </TraceEvent>
) : showWrap ? ( ) : showWrap ? (
<ButtonPrimary disabled={Boolean(wrapInputError)} onClick={onWrap}> <TraceEvent
{wrapInputError ? ( events={[Event.onClick]}
<WrapErrorText wrapInputError={wrapInputError} /> name={EventName.WRAP_TOKEN_TXN_SUBMITTED}
) : wrapType === WrapType.WRAP ? ( element={ElementName.WRAP_TOKEN_BUTTON}
<Trans>Wrap</Trans> properties={formatWrapTokenTxnSubmittedEventProperties(
) : wrapType === WrapType.UNWRAP ? ( currencies[Field.INPUT],
<Trans>Unwrap</Trans> currencies[Field.OUTPUT],
) : null} parsedAmount
</ButtonPrimary> )}
shouldLogImpression={!Boolean(wrapInputError)}
>
<ButtonPrimary disabled={Boolean(wrapInputError)} onClick={onWrap}>
{wrapInputError ? (
<WrapErrorText wrapInputError={wrapInputError} />
) : wrapType === WrapType.WRAP ? (
<Trans>Wrap</Trans>
) : wrapType === WrapType.UNWRAP ? (
<Trans>Unwrap</Trans>
) : null}
</ButtonPrimary>
</TraceEvent>
) : routeNotFound && userHasSpecifiedInputOutput && !routeIsLoading && !routeIsSyncing ? ( ) : routeNotFound && userHasSpecifiedInputOutput && !routeIsLoading && !routeIsSyncing ? (
<GreyCard style={{ textAlign: 'center' }}> <GreyCard style={{ textAlign: 'center' }}>
<ThemedText.DeprecatedMain mb="4px"> <ThemedText.DeprecatedMain mb="4px">
...@@ -637,53 +683,57 @@ export default function Swap() { ...@@ -637,53 +683,57 @@ export default function Swap() {
) : showApproveFlow ? ( ) : showApproveFlow ? (
<AutoRow style={{ flexWrap: 'nowrap', width: '100%' }}> <AutoRow style={{ flexWrap: 'nowrap', width: '100%' }}>
<AutoColumn style={{ width: '100%' }} gap="12px"> <AutoColumn style={{ width: '100%' }} gap="12px">
<ButtonConfirmed <TraceEvent
onClick={handleApprove} events={[Event.onClick]}
disabled={ name={EventName.APPROVE_TOKEN_TXN_SUBMITTED}
approvalState !== ApprovalState.NOT_APPROVED || element={ElementName.APPROVE_TOKEN_BUTTON}
approvalSubmitted || properties={formatApproveTokenTxnSubmittedEventProperties(approvalOptimizedTrade)}
signatureState === UseERC20PermitState.SIGNED shouldLogImpression={!approveTokenButtonDisabled}
}
width="100%"
altDisabledStyle={approvalState === ApprovalState.PENDING} // show solid button while waiting
confirmed={
approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
}
> >
<AutoRow justify="space-between" style={{ flexWrap: 'nowrap' }}> <ButtonConfirmed
<span style={{ display: 'flex', alignItems: 'center' }}> onClick={handleApprove}
<CurrencyLogo disabled={approveTokenButtonDisabled}
currency={currencies[Field.INPUT]} width="100%"
size={'20px'} altDisabledStyle={approvalState === ApprovalState.PENDING} // show solid button while waiting
style={{ marginRight: '8px', flexShrink: 0 }} confirmed={
/> approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
{/* we need to shorten this string on mobile */} }
{approvalState === ApprovalState.APPROVED || >
signatureState === UseERC20PermitState.SIGNED ? ( <AutoRow justify="space-between" style={{ flexWrap: 'nowrap' }}>
<Trans>You can now trade {currencies[Field.INPUT]?.symbol}</Trans> <span style={{ display: 'flex', alignItems: 'center' }}>
<CurrencyLogo
currency={currencies[Field.INPUT]}
size={'20px'}
style={{ marginRight: '8px', flexShrink: 0 }}
/>
{/* we need to shorten this string on mobile */}
{approvalState === ApprovalState.APPROVED ||
signatureState === UseERC20PermitState.SIGNED ? (
<Trans>You can now trade {currencies[Field.INPUT]?.symbol}</Trans>
) : (
<Trans>Allow the Uniswap Protocol to use your {currencies[Field.INPUT]?.symbol}</Trans>
)}
</span>
{approvalState === ApprovalState.PENDING ? (
<Loader stroke="white" />
) : (approvalSubmitted && approvalState === ApprovalState.APPROVED) ||
signatureState === UseERC20PermitState.SIGNED ? (
<CheckCircle size="20" color={theme.deprecated_green1} />
) : ( ) : (
<Trans>Allow the Uniswap Protocol to use your {currencies[Field.INPUT]?.symbol}</Trans> <MouseoverTooltip
text={
<Trans>
You must give the Uniswap smart contracts permission to use your{' '}
{currencies[Field.INPUT]?.symbol}. You only have to do this once per token.
</Trans>
}
>
<HelpCircle size="20" color={'deprecated_white'} style={{ marginLeft: '8px' }} />
</MouseoverTooltip>
)} )}
</span> </AutoRow>
{approvalState === ApprovalState.PENDING ? ( </ButtonConfirmed>
<Loader stroke="white" /> </TraceEvent>
) : (approvalSubmitted && approvalState === ApprovalState.APPROVED) ||
signatureState === UseERC20PermitState.SIGNED ? (
<CheckCircle size="20" color={theme.deprecated_green1} />
) : (
<MouseoverTooltip
text={
<Trans>
You must give the Uniswap smart contracts permission to use your{' '}
{currencies[Field.INPUT]?.symbol}. You only have to do this once per token.
</Trans>
}
>
<HelpCircle size="20" color={'deprecated_white'} style={{ marginLeft: '8px' }} />
</MouseoverTooltip>
)}
</AutoRow>
</ButtonConfirmed>
<ButtonError <ButtonError
onClick={() => { onClick={() => {
if (isExpertMode) { if (isExpertMode) {
......
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