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

feat: log approve token and wrap token events directly in hooks (#4258)

* init

* clean up

* remove unnecessary constants

* undo yarn.lock change
parent a02099f9
...@@ -83,7 +83,6 @@ export const enum ModalName { ...@@ -83,7 +83,6 @@ 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',
...@@ -96,7 +95,6 @@ export const enum ElementName { ...@@ -96,7 +95,6 @@ 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.
} }
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Currency } from '@uniswap/sdk-core' import { Currency } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { sendAnalyticsEvent } from 'components/AmplitudeAnalytics'
import { EventName } from 'components/AmplitudeAnalytics/constants'
import { formatToDecimal, getTokenAddress } from 'components/AmplitudeAnalytics/utils'
import useNativeCurrency from 'lib/hooks/useNativeCurrency' import useNativeCurrency from 'lib/hooks/useNativeCurrency'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
import { useMemo } from 'react' import { useMemo } from 'react'
...@@ -75,6 +78,15 @@ export default function useWrapCallback( ...@@ -75,6 +78,15 @@ export default function useWrapCallback(
const hasInputAmount = Boolean(inputAmount?.greaterThan('0')) const hasInputAmount = Boolean(inputAmount?.greaterThan('0'))
const sufficientBalance = inputAmount && balance && !balance.lessThan(inputAmount) const sufficientBalance = inputAmount && balance && !balance.lessThan(inputAmount)
const eventProperties = {
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: inputAmount ? formatToDecimal(inputAmount, inputAmount?.currency.decimals) : undefined,
}
if (inputCurrency.isNative && weth.equals(outputCurrency)) { if (inputCurrency.isNative && weth.equals(outputCurrency)) {
return { return {
wrapType: WrapType.WRAP, wrapType: WrapType.WRAP,
...@@ -89,6 +101,7 @@ export default function useWrapCallback( ...@@ -89,6 +101,7 @@ export default function useWrapCallback(
currencyAmountRaw: inputAmount?.quotient.toString(), currencyAmountRaw: inputAmount?.quotient.toString(),
chainId, chainId,
}) })
sendAnalyticsEvent(EventName.WRAP_TOKEN_TXN_SUBMITTED, { ...eventProperties, type: WrapType.WRAP })
} catch (error) { } catch (error) {
console.error('Could not deposit', error) console.error('Could not deposit', error)
} }
...@@ -114,6 +127,7 @@ export default function useWrapCallback( ...@@ -114,6 +127,7 @@ export default function useWrapCallback(
currencyAmountRaw: inputAmount?.quotient.toString(), currencyAmountRaw: inputAmount?.quotient.toString(),
chainId, chainId,
}) })
sendAnalyticsEvent(EventName.WRAP_TOKEN_TXN_SUBMITTED, { ...eventProperties, type: WrapType.UNWRAP })
} catch (error) { } catch (error) {
console.error('Could not withdraw', error) console.error('Could not withdraw', error)
} }
......
...@@ -2,6 +2,9 @@ import { MaxUint256 } from '@ethersproject/constants' ...@@ -2,6 +2,9 @@ import { MaxUint256 } from '@ethersproject/constants'
import { TransactionResponse } from '@ethersproject/providers' import { TransactionResponse } from '@ethersproject/providers'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { sendAnalyticsEvent } from 'components/AmplitudeAnalytics'
import { EventName } from 'components/AmplitudeAnalytics/constants'
import { getTokenAddress } from 'components/AmplitudeAnalytics/utils'
import { useTokenContract } from 'hooks/useContract' import { useTokenContract } from 'hooks/useContract'
import { useTokenAllowance } from 'hooks/useTokenAllowance' import { useTokenAllowance } from 'hooks/useTokenAllowance'
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
...@@ -88,11 +91,19 @@ export function useApproval( ...@@ -88,11 +91,19 @@ export function useApproval(
.approve(spender, useExact ? amountToApprove.quotient.toString() : MaxUint256, { .approve(spender, useExact ? amountToApprove.quotient.toString() : MaxUint256, {
gasLimit: calculateGasMargin(estimatedGas), gasLimit: calculateGasMargin(estimatedGas),
}) })
.then((response) => ({ .then((response) => {
response, const eventProperties = {
tokenAddress: token.address, chain_id: chainId,
spenderAddress: spender, token_symbol: token?.symbol,
})) token_address: getTokenAddress(token),
}
sendAnalyticsEvent(EventName.APPROVE_TOKEN_TXN_SUBMITTED, eventProperties)
return {
response,
tokenAddress: token.address,
spenderAddress: spender,
}
})
.catch((error: Error) => { .catch((error: Error) => {
logFailure(error) logFailure(error)
throw error throw error
......
...@@ -85,37 +85,6 @@ export function getIsValidSwapQuote( ...@@ -85,37 +85,6 @@ 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
...@@ -653,27 +622,15 @@ export default function Swap() { ...@@ -653,27 +622,15 @@ export default function Swap() {
</ButtonLight> </ButtonLight>
</TraceEvent> </TraceEvent>
) : showWrap ? ( ) : showWrap ? (
<TraceEvent <ButtonPrimary disabled={Boolean(wrapInputError)} onClick={onWrap}>
events={[Event.onClick]} {wrapInputError ? (
name={EventName.WRAP_TOKEN_TXN_SUBMITTED} <WrapErrorText wrapInputError={wrapInputError} />
element={ElementName.WRAP_TOKEN_BUTTON} ) : wrapType === WrapType.WRAP ? (
properties={formatWrapTokenTxnSubmittedEventProperties( <Trans>Wrap</Trans>
currencies[Field.INPUT], ) : wrapType === WrapType.UNWRAP ? (
currencies[Field.OUTPUT], <Trans>Unwrap</Trans>
parsedAmount ) : null}
)} </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">
...@@ -683,57 +640,49 @@ export default function Swap() { ...@@ -683,57 +640,49 @@ 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">
<TraceEvent <ButtonConfirmed
events={[Event.onClick]} onClick={handleApprove}
name={EventName.APPROVE_TOKEN_TXN_SUBMITTED} disabled={approveTokenButtonDisabled}
element={ElementName.APPROVE_TOKEN_BUTTON} width="100%"
properties={formatApproveTokenTxnSubmittedEventProperties(approvalOptimizedTrade)} altDisabledStyle={approvalState === ApprovalState.PENDING} // show solid button while waiting
shouldLogImpression={!approveTokenButtonDisabled} confirmed={
approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED
}
> >
<ButtonConfirmed <AutoRow justify="space-between" style={{ flexWrap: 'nowrap' }}>
onClick={handleApprove} <span style={{ display: 'flex', alignItems: 'center' }}>
disabled={approveTokenButtonDisabled} <CurrencyLogo
width="100%" currency={currencies[Field.INPUT]}
altDisabledStyle={approvalState === ApprovalState.PENDING} // show solid button while waiting size={'20px'}
confirmed={ style={{ marginRight: '8px', flexShrink: 0 }}
approvalState === ApprovalState.APPROVED || signatureState === UseERC20PermitState.SIGNED />
} {/* we need to shorten this string on mobile */}
> {approvalState === ApprovalState.APPROVED ||
<AutoRow justify="space-between" style={{ flexWrap: 'nowrap' }}> signatureState === UseERC20PermitState.SIGNED ? (
<span style={{ display: 'flex', alignItems: 'center' }}> <Trans>You can now trade {currencies[Field.INPUT]?.symbol}</Trans>
<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} />
) : ( ) : (
<MouseoverTooltip <Trans>Allow the Uniswap Protocol to use your {currencies[Field.INPUT]?.symbol}</Trans>
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> </span>
</ButtonConfirmed> {approvalState === ApprovalState.PENDING ? (
</TraceEvent> <Loader stroke="white" />
) : (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