Skip to content

Commit

Permalink
feat(earn): add gas related analytics properties (#5447)
Browse files Browse the repository at this point in the history
### Description

Adding gas fields to analytics properties similar to swaps for the earn
deposit transaction

### Test plan

Unit tests

### Related issues

N/A

### Backwards compatibility

Yes

### Network scalability

If a new NetworkId and/or Network are added in the future, the changes
in this PR will:

- [x] Continue to work without code changes, OR trigger a compilation
error (guaranteeing we find it when a new network is added)
  • Loading branch information
satish-ravi committed May 21, 2024
1 parent e5f3242 commit a36105f
Show file tree
Hide file tree
Showing 6 changed files with 233 additions and 105 deletions.
20 changes: 16 additions & 4 deletions src/analytics/Properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,17 @@ interface EarnWithdrawProperties {
rewards: SerializableRewardsInfo[]
}

// Adds `deposit` prefix to all properties of TxReceiptProperties
type DepositTxReceiptProperties = PrefixedTxReceiptProperties<'deposit'>

export type EarnDepositTxsReceiptProperties = Partial<ApproveTxReceiptProperties> &
Partial<DepositTxReceiptProperties> &
Partial<{
gasUsed: number // Gas used by the deposit (approve + deposit)
gasFee: number | undefined // Actual gas fee of the deposit (approve + deposit) in feeCurrency (decimal value)
gasFeeUsd: number | undefined // Actual gas fee of the deposit (approve + deposit) in USD
}>

interface EarnEventsProperties {
[EarnEvents.earn_cta_press]: undefined
[EarnEvents.earn_add_crypto_action_press]: {
Expand All @@ -1606,10 +1617,11 @@ interface EarnEventsProperties {
[EarnEvents.earn_deposit_complete]: undefined
[EarnEvents.earn_deposit_cancel]: undefined
[EarnEvents.earn_deposit_submit_start]: EarnDepositProperties
[EarnEvents.earn_deposit_submit_success]: EarnDepositProperties
[EarnEvents.earn_deposit_submit_error]: EarnDepositProperties & {
error: string
}
[EarnEvents.earn_deposit_submit_success]: EarnDepositProperties & EarnDepositTxsReceiptProperties
[EarnEvents.earn_deposit_submit_error]: EarnDepositProperties &
EarnDepositTxsReceiptProperties & {
error: string
}
[EarnEvents.earn_deposit_submit_cancel]: EarnDepositProperties
[EarnEvents.earn_view_pools_press]: undefined
[EarnEvents.earn_enter_amount_info_press]: undefined
Expand Down
75 changes: 63 additions & 12 deletions src/earn/saga.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,17 @@ describe('depositSubmitSaga', () => {
value: '100',
data: '0x01',
gas: '20000',
maxFeePerGas: '12000000000',
_baseFeePerGas: '6000000000',
}
const serializableDepositTx: SerializableTransactionRequest = {
from: '0xa',
to: '0xc',
value: '100',
data: '0x02',
gas: '50000',
maxFeePerGas: '12000000000',
_baseFeePerGas: '6000000000',
}

const mockStandbyHandler = jest.fn()
Expand Down Expand Up @@ -160,6 +164,46 @@ describe('depositSubmitSaga', () => {
providerId: 'aave-v3',
}

const expectedApproveGasAnalyticsProperties = {
approveTxCumulativeGasUsed: 3129217,
approveTxEffectiveGasPrice: 5000000000,
approveTxEstimatedGasFee: 0.00012,
approveTxEstimatedGasFeeUsd: 0.18,
approveTxFeeCurrency: undefined,
approveTxFeeCurrencySymbol: 'ETH',
approveTxGas: 20000,
approveTxGasFee: 0.00025789,
approveTxGasFeeUsd: 0.386835,
approveTxGasUsed: 51578,
approveTxHash: '0x1',
approveTxMaxGasFee: 0.00024,
approveTxMaxGasFeeUsd: 0.36,
}

const expectedDepositGasAnalyticsProperties = {
depositTxCumulativeGasUsed: 3899547,
depositTxEffectiveGasPrice: 5000000000,
depositTxEstimatedGasFee: 0.0003,
depositTxEstimatedGasFeeUsd: 0.45,
depositTxFeeCurrency: undefined,
depositTxFeeCurrencySymbol: 'ETH',
depositTxGas: 50000,
depositTxGasFee: 0.00185837,
depositTxGasFeeUsd: 2.787555,
depositTxGasUsed: 371674,
depositTxHash: '0x2',
depositTxMaxGasFee: 0.0006,
depositTxMaxGasFeeUsd: 0.9,
}

const expectedCumulativeGasAnalyticsProperties = {
gasFee: 0.00211626,
gasFeeUsd: 3.17439,
gasUsed: 423252,
...expectedApproveGasAnalyticsProperties,
...expectedDepositGasAnalyticsProperties,
}

beforeEach(() => {
jest.clearAllMocks()
})
Expand Down Expand Up @@ -192,10 +236,10 @@ describe('depositSubmitSaga', () => {
EarnEvents.earn_deposit_submit_start,
expectedAnalyticsProps
)
expect(ValoraAnalytics.track).toHaveBeenCalledWith(
EarnEvents.earn_deposit_submit_success,
expectedAnalyticsProps
)
expect(ValoraAnalytics.track).toHaveBeenCalledWith(EarnEvents.earn_deposit_submit_success, {
...expectedAnalyticsProps,
...expectedCumulativeGasAnalyticsProperties,
})
})

it('sends only deposit transaction, navigates home and dispatches the success action', async () => {
Expand All @@ -221,10 +265,13 @@ describe('depositSubmitSaga', () => {
EarnEvents.earn_deposit_submit_start,
expectedAnalyticsProps
)
expect(ValoraAnalytics.track).toHaveBeenCalledWith(
EarnEvents.earn_deposit_submit_success,
expectedAnalyticsProps
)
expect(ValoraAnalytics.track).toHaveBeenCalledWith(EarnEvents.earn_deposit_submit_success, {
...expectedAnalyticsProps,
...expectedDepositGasAnalyticsProperties,
gasFee: 0.00185837,
gasFeeUsd: 2.787555,
gasUsed: 371674,
})
})

it('dispatches cancel action if pin input is cancelled and does not navigate home', async () => {
Expand Down Expand Up @@ -284,10 +331,13 @@ describe('depositSubmitSaga', () => {
EarnEvents.earn_deposit_submit_start,
expectedAnalyticsProps
)
expect(ValoraAnalytics.track).toHaveBeenCalledWith(EarnEvents.earn_deposit_submit_error, {
...expectedAnalyticsProps,
error: 'Transaction failed',
})
expect(ValoraAnalytics.track).toHaveBeenCalledWith(
EarnEvents.earn_deposit_submit_error,
expect.objectContaining({
...expectedAnalyticsProps,
error: 'Transaction failed',
})
)
})

it('dispatches error action and navigates home if deposit transaction status is reverted', async () => {
Expand Down Expand Up @@ -327,6 +377,7 @@ describe('depositSubmitSaga', () => {
expect(ValoraAnalytics.track).toHaveBeenCalledWith(EarnEvents.earn_deposit_submit_error, {
...expectedAnalyticsProps,
error: 'Deposit transaction reverted: 0x2',
...expectedCumulativeGasAnalyticsProperties,
})
})
})
Expand Down
64 changes: 60 additions & 4 deletions src/earn/saga.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PayloadAction } from '@reduxjs/toolkit'
import BigNumber from 'bignumber.js'
import erc20 from 'src/abis/IERC20'
import { EarnEvents } from 'src/analytics/Events'
import { EarnDepositTxsReceiptProperties } from 'src/analytics/Properties'
import ValoraAnalytics from 'src/analytics/ValoraAnalytics'
import {
depositCancel,
Expand All @@ -18,20 +19,56 @@ import { navigateHome } from 'src/navigator/NavigationService'
import { CANCELLED_PIN_INPUT } from 'src/pincode/authentication'
import { vibrateError } from 'src/styles/hapticFeedback'
import { getTokenInfo } from 'src/tokens/saga'
import { tokensByIdSelector } from 'src/tokens/selectors'
import { TokenBalances } from 'src/tokens/slice'
import { BaseStandbyTransaction } from 'src/transactions/actions'
import { TokenTransactionTypeV2, newTransactionContext } from 'src/transactions/types'
import {
NetworkId,
TokenTransactionTypeV2,
TrackedTx,
newTransactionContext,
} from 'src/transactions/types'
import {
getPrefixedTxAnalyticsProperties,
getTxReceiptAnalyticsProperties,
} from 'src/transactions/utils'
import Logger from 'src/utils/Logger'
import { ensureError } from 'src/utils/ensureError'
import { safely } from 'src/utils/safely'
import { publicClient } from 'src/viem'
import { getPreparedTransactions } from 'src/viem/preparedTransactionSerialization'
import { sendPreparedTransactions } from 'src/viem/saga'
import networkConfig, { networkIdToNetwork } from 'src/web3/networkConfig'
import { all, call, put, takeLeading } from 'typed-redux-saga'
import { all, call, put, select, takeLeading } from 'typed-redux-saga'
import { decodeFunctionData } from 'viem'

const TAG = 'earn/saga'

function getDepositTxsReceiptAnalyticsProperties(
trackedTxs: TrackedTx[],
networkId: NetworkId,
tokensById: TokenBalances
): EarnDepositTxsReceiptProperties {
const txs = trackedTxs.map((trackedTx) =>
getTxReceiptAnalyticsProperties(trackedTx, networkId, tokensById)
)

const approveTx = trackedTxs.length > 1 ? txs[0] : undefined
const depositTx = trackedTxs.length > 0 ? txs[txs.length - 1] : undefined

return {
...getPrefixedTxAnalyticsProperties(approveTx || {}, 'approve'),
...getPrefixedTxAnalyticsProperties(depositTx || {}, 'deposit'),
gasUsed: depositTx?.txGasUsed
? txs.reduce((sum, tx) => sum + (tx.txGasUsed || 0), 0)
: undefined,
gasFee: depositTx?.txGasFee ? txs.reduce((sum, tx) => sum + (tx.txGasFee || 0), 0) : undefined,
gasFeeUsd: depositTx?.txGasFeeUsd
? txs.reduce((sum, tx) => sum + (tx.txGasFeeUsd || 0), 0)
: undefined,
}
}

export function* depositSubmitSaga(action: PayloadAction<DepositInfo>) {
const { tokenId, preparedTransactions: serializablePreparedTransactions, amount } = action.payload

Expand All @@ -44,6 +81,9 @@ export function* depositSubmitSaga(action: PayloadAction<DepositInfo>) {
return
}

const tokensById = yield* select((state) => tokensByIdSelector(state, [tokenInfo.networkId]))

const trackedTxs: TrackedTx[] = []
const networkId = tokenInfo.networkId
const commonAnalyticsProps = {
tokenId,
Expand All @@ -60,6 +100,14 @@ export function* depositSubmitSaga(action: PayloadAction<DepositInfo>) {
`Starting deposit for token ${tokenId}, total transactions: ${preparedTransactions.length}`
)

for (const tx of preparedTransactions) {
trackedTxs.push({
tx,
txHash: undefined,
txReceipt: undefined,
})
}

const createDepositStandbyTxHandlers = []

if (preparedTransactions.length > 1 && preparedTransactions[0].data) {
Expand Down Expand Up @@ -126,6 +174,9 @@ export function* depositSubmitSaga(action: PayloadAction<DepositInfo>) {
networkId,
createDepositStandbyTxHandlers
)
txHashes.forEach((txHash, i) => {
trackedTxs[i].txHash = txHash
})

Logger.debug(
`${TAG}/depositSubmitSaga`,
Expand All @@ -146,6 +197,7 @@ export function* depositSubmitSaga(action: PayloadAction<DepositInfo>) {
})
)
txReceipts.forEach((receipt, index) => {
trackedTxs[index].txReceipt = receipt
Logger.debug(
`${TAG}/depositSubmitSaga`,
`Received transaction receipt ${index + 1} of ${txReceipts.length}`,
Expand All @@ -158,7 +210,10 @@ export function* depositSubmitSaga(action: PayloadAction<DepositInfo>) {
throw new Error(`Deposit transaction reverted: ${depositTxReceipt?.transactionHash}`)
}

ValoraAnalytics.track(EarnEvents.earn_deposit_submit_success, commonAnalyticsProps)
ValoraAnalytics.track(EarnEvents.earn_deposit_submit_success, {
...commonAnalyticsProps,
...getDepositTxsReceiptAnalyticsProperties(trackedTxs, networkId, tokensById),
})
yield* put(depositSuccess())
} catch (err) {
if (err === CANCELLED_PIN_INPUT) {
Expand All @@ -174,6 +229,7 @@ export function* depositSubmitSaga(action: PayloadAction<DepositInfo>) {
ValoraAnalytics.track(EarnEvents.earn_deposit_submit_error, {
...commonAnalyticsProps,
error: error.message,
...getDepositTxsReceiptAnalyticsProperties(trackedTxs, networkId, tokensById),
})

// Only vibrate if we haven't already submitted the transaction
Expand Down Expand Up @@ -278,7 +334,7 @@ export function* withdrawSubmitSaga(action: PayloadAction<WithdrawInfo>) {
)

Logger.debug(
`${TAG}/withd`,
`${TAG}/withdraw`,
'Successfully sent withdraw transaction(s) to the network',
txHashes
)
Expand Down

0 comments on commit a36105f

Please sign in to comment.