From 935409cf1510d3dc94cc2aebe4f4cf53f9b2e2e8 Mon Sep 17 00:00:00 2001 From: Tom McGuire Date: Fri, 25 Oct 2024 12:24:52 -0700 Subject: [PATCH 1/8] feat(earn): prepare transactions and use on confirmation screen --- src/earn/EarnConfirmationScreen.tsx | 64 ++++++++--- src/earn/EarnEnterAmount.tsx | 13 ++- src/earn/hooks.ts | 61 +++++++++-- src/earn/prepareTransactions.ts | 164 +++++++++++++++++----------- 4 files changed, 207 insertions(+), 95 deletions(-) diff --git a/src/earn/EarnConfirmationScreen.tsx b/src/earn/EarnConfirmationScreen.tsx index 21a9d159f47..619980dd06e 100644 --- a/src/earn/EarnConfirmationScreen.tsx +++ b/src/earn/EarnConfirmationScreen.tsx @@ -1,6 +1,6 @@ import { NativeStackScreenProps } from '@react-navigation/native-stack' import BigNumber from 'bignumber.js' -import React, { useMemo } from 'react' +import React, { useEffect, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { SafeAreaView, ScrollView, StyleSheet, Text, View } from 'react-native' import SkeletonPlaceholder from 'react-native-skeleton-placeholder' @@ -10,7 +10,7 @@ import Button, { BtnSizes } from 'src/components/Button' import InLineNotification, { NotificationVariant } from 'src/components/InLineNotification' import TokenDisplay from 'src/components/TokenDisplay' import TokenIcon, { IconSize } from 'src/components/TokenIcon' -import { usePrepareWithdrawAndClaimTransactions } from 'src/earn/hooks' +import { usePrepareTransactions } from 'src/earn/hooks' import { withdrawStatusSelector } from 'src/earn/selectors' import { withdrawStart } from 'src/earn/slice' import { EarnActiveAction } from 'src/earn/types' @@ -29,6 +29,7 @@ import { Spacing } from 'src/styles/styles' import { useTokenInfo } from 'src/tokens/hooks' import { feeCurrenciesSelector } from 'src/tokens/selectors' import { TokenBalance } from 'src/tokens/slice' +import Logger from 'src/utils/Logger' import { getFeeCurrencyAndAmounts } from 'src/viem/prepareTransactions' import { getSerializablePreparedTransactions } from 'src/viem/preparedTransactionSerialization' import { walletAddressSelector } from 'src/web3/selectors' @@ -36,6 +37,9 @@ import { isAddress } from 'viem' type Props = NativeStackScreenProps +const TAG = 'EarnConfirmationScreen' +const FETCH_UPDATED_TRANSACTIONS_DEBOUNCE_TIME = 250 + export default function EarnConfirmationScreen({ route }: Props) { const { t } = useTranslation() const dispatch = useDispatch() @@ -74,20 +78,50 @@ export default function EarnConfirmationScreen({ route }: Props) { [withdrawToken, pool.pricePerShare, inputAmount] ) - // Will need this to handle preparing a claim transaction, a withdrawal transaction and a withdrawal and claim transaction const { - result: prepareTransactionsResult, - loading: isPreparingTransactions, - error: prepareTransactionError, - } = usePrepareWithdrawAndClaimTransactions({ - amount: new BigNumber(withdrawAmountInDepositToken).dividedBy(pool.pricePerShare[0]).toString(), - pool, - walletAddress, - feeCurrencies, - hooksApiUrl, - rewardsPositions, - useMax, - }) + // @ts-expect-error prepareTransactionsResult & swapTransaction are only set when mode === 'deposit' or 'swap-deposit' + prepareTransactionsResult: { prepareTransactionsResult, swapTransaction } = {}, + refreshPreparedTransactions, + clearPreparedTransactions, + prepareTransactionError, + isPreparingTransactions, + } = usePrepareTransactions(mode) + + const handleRefreshPreparedTransactions = ( + amount: BigNumber, + token: TokenBalance, + feeCurrencies: TokenBalance[] + ) => { + if (!walletAddress || !isAddress(walletAddress)) { + Logger.error(TAG, 'Wallet address not set. Cannot refresh prepared transactions.') + return + } + + return refreshPreparedTransactions({ + amount: new BigNumber(amount).dividedBy(pool.pricePerShare[0]).toString(), + token, + walletAddress, + feeCurrencies, + pool, + hooksApiUrl, + // Mode === shortcutId, except for exit which is withdraw + shortcutId: mode === 'exit' ? 'withdraw' : mode, + useMax, + }) + } + + useEffect(() => { + clearPreparedTransactions() + + const debouncedRefreshTransactions = setTimeout(() => { + return handleRefreshPreparedTransactions( + new BigNumber(withdrawAmountInDepositToken), + withdrawToken, + feeCurrencies + ) + }, FETCH_UPDATED_TRANSACTIONS_DEBOUNCE_TIME) + return () => clearTimeout(debouncedRefreshTransactions) + }, [withdrawAmountInDepositToken, depositToken, feeCurrencies]) const onPress = () => { if (prepareTransactionsResult?.type !== 'possible') { diff --git a/src/earn/EarnEnterAmount.tsx b/src/earn/EarnEnterAmount.tsx index 74192bdefcf..104c51d3b30 100644 --- a/src/earn/EarnEnterAmount.tsx +++ b/src/earn/EarnEnterAmount.tsx @@ -21,7 +21,7 @@ import TokenIcon, { IconSize } from 'src/components/TokenIcon' import Touchable from 'src/components/Touchable' import CustomHeader from 'src/components/header/CustomHeader' import EarnDepositBottomSheet from 'src/earn/EarnDepositBottomSheet' -import { usePrepareTransactions } from 'src/earn/prepareTransactions' +import { usePrepareTransactions } from 'src/earn/hooks' import { getSwapToAmountInDecimals } from 'src/earn/utils' import { CICOFlow } from 'src/fiatExchanges/utils' import ArrowRightThick from 'src/icons/ArrowRightThick' @@ -144,6 +144,7 @@ function EarnEnterAmount({ route }: Props) { } const { + // @ts-expect-error prepareTransactionsResult & swapTransaction are only set when mode === 'deposit' or 'swap-deposit' prepareTransactionsResult: { prepareTransactionsResult, swapTransaction } = {}, refreshPreparedTransactions, clearPreparedTransactions, @@ -483,11 +484,17 @@ function EarnEnterAmount({ route }: Props) { })} description={t('earnFlow.enterAmount.notEnoughBalanceForGasWarning.description', { feeTokenSymbol: prepareTransactionsResult.feeCurrencies[0].symbol, - network: NETWORK_NAMES[prepareTransactionsResult.feeCurrencies[0].networkId], + network: + NETWORK_NAMES[ + prepareTransactionsResult.feeCurrencies[0].networkId as keyof typeof NETWORK_NAMES + ], })} ctaLabel={t('earnFlow.enterAmount.notEnoughBalanceForGasWarning.noGasCta', { feeTokenSymbol: feeCurrencies[0].symbol, - network: NETWORK_NAMES[prepareTransactionsResult.feeCurrencies[0].networkId], + network: + NETWORK_NAMES[ + prepareTransactionsResult.feeCurrencies[0].networkId as keyof typeof NETWORK_NAMES + ], })} onPressCta={() => { AppAnalytics.track(EarnEvents.earn_deposit_add_gas_press, { diff --git a/src/earn/hooks.ts b/src/earn/hooks.ts index 0af004bb3de..b56cf9b5372 100644 --- a/src/earn/hooks.ts +++ b/src/earn/hooks.ts @@ -1,7 +1,12 @@ import { useMemo } from 'react' -import { useAsync } from 'react-async-hook' -import { prepareWithdrawAndClaimTransactions } from 'src/earn/prepareTransactions' -import { PrepareWithdrawAndClaimParams } from 'src/earn/types' +import { useAsync, useAsyncCallback } from 'react-async-hook' +import { + prepareClaimTransactions, + prepareDepositTransactions, + prepareWithdrawAndClaimTransactions, + prepareWithdrawTransactions, +} from 'src/earn/prepareTransactions' +import { EarnActiveAction } from 'src/earn/types' import { fetchExchanges } from 'src/fiatExchanges/utils' import { isAppSwapsEnabledSelector } from 'src/navigator/selectors' import { userLocationDataSelector } from 'src/networkInfo/selectors' @@ -17,15 +22,6 @@ import { ensureError } from 'src/utils/ensureError' const TAG = 'earn/hooks' -export function usePrepareWithdrawAndClaimTransactions(params: PrepareWithdrawAndClaimParams) { - return useAsync(() => prepareWithdrawAndClaimTransactions(params), [], { - onError: (err) => { - const error = ensureError(err) - Logger.error(TAG, 'usePrepareWithdrawAndClaimTransactions', error) - }, - }) -} - export function useEarnPositionProviderName(providerId: string) { const pools = useSelector(earnPositionsSelector) const providerName = pools.find((pool) => pool.appId === providerId)?.appName @@ -94,3 +90,44 @@ export function useDepositEntrypointInfo({ }, [asyncExchanges.result]) return { hasDepositToken, hasTokensOnSameNetwork, hasTokensOnOtherNetworks, canCashIn, exchanges } } + +export function usePrepareTransactions(mode: EarnActiveAction) { + const getTransactionFunction = () => { + switch (mode) { + case 'deposit': + case 'swap-deposit': + return prepareDepositTransactions + case 'withdraw': + return prepareWithdrawTransactions + case 'claim-rewards': + return prepareClaimTransactions + case 'exit': + return prepareWithdrawAndClaimTransactions + default: + throw new Error(`Invalid mode: ${mode}`) + } + } + + const prepareTransactions = useAsyncCallback( + async (args) => { + // Get the appropriate function based on the mode + const prepareFunction = getTransactionFunction() + // Ensure the function is called with the necessary arguments + return prepareFunction(args) + }, + { + onError: (err) => { + const error = ensureError(err) + Logger.error(TAG, 'usePrepareTransactions - Error:', error) + }, + } + ) + + return { + prepareTransactionsResult: prepareTransactions.result, + refreshPreparedTransactions: prepareTransactions.execute, + clearPreparedTransactions: prepareTransactions.reset, + prepareTransactionError: prepareTransactions.error, + isPreparingTransactions: prepareTransactions.loading, + } +} diff --git a/src/earn/prepareTransactions.ts b/src/earn/prepareTransactions.ts index c60ba28a936..5cc6d99ac8c 100644 --- a/src/earn/prepareTransactions.ts +++ b/src/earn/prepareTransactions.ts @@ -1,19 +1,16 @@ import BigNumber from 'bignumber.js' -import _ from 'lodash' -import { useAsyncCallback } from 'react-async-hook' -import { EarnActiveAction, PrepareWithdrawAndClaimParams } from 'src/earn/types' +import { EarnActiveAction } from 'src/earn/types' import { isGasSubsidizedForNetwork } from 'src/earn/utils' import { triggerShortcutRequest } from 'src/positions/saga' import { RawShortcutTransaction } from 'src/positions/slice' import { rawShortcutTransactionsToTransactionRequests } from 'src/positions/transactions' -import { EarnPosition } from 'src/positions/types' +import { EarnPosition, Position } from 'src/positions/types' import { getDynamicConfigParams } from 'src/statsig' import { DynamicConfigs } from 'src/statsig/constants' import { StatsigDynamicConfigs } from 'src/statsig/types' import { SwapTransaction } from 'src/swap/types' import { TokenBalance } from 'src/tokens/slice' import Logger from 'src/utils/Logger' -import { ensureError } from 'src/utils/ensureError' import { prepareTransactions } from 'src/viem/prepareTransactions' import { Address } from 'viem' @@ -36,6 +33,7 @@ export async function prepareDepositTransactions({ hooksApiUrl: string shortcutId: Exclude }) { + const { appId, networkId } = pool const { enableAppFee } = getDynamicConfigParams(DynamicConfigs[StatsigDynamicConfigs.SWAP_CONFIG]) const args = shortcutId === 'deposit' @@ -64,8 +62,8 @@ export async function prepareDepositTransactions({ }: { transactions: RawShortcutTransaction[]; dataProps?: { swapTransaction: SwapTransaction } } = await triggerShortcutRequest(hooksApiUrl, { address: walletAddress, - appId: pool.appId, - networkId: pool.networkId, + appId, + networkId, shortcutId, ...args, ...pool.shortcutTriggerArgs?.[shortcutId], @@ -94,15 +92,21 @@ export async function prepareDepositTransactions({ } export async function prepareWithdrawAndClaimTransactions({ - pool, + token, walletAddress, feeCurrencies, + pool, hooksApiUrl, rewardsPositions, - amount, - useMax = true, -}: PrepareWithdrawAndClaimParams) { - const { dataProps, balance, appId, networkId, shortcutTriggerArgs } = pool +}: { + token: TokenBalance + walletAddress: Address + feeCurrencies: TokenBalance[] + pool: EarnPosition + hooksApiUrl: string + rewardsPositions?: Position[] +}) { + const { appId, balance, dataProps, networkId, shortcutTriggerArgs } = pool const { transactions: withdrawTransactions }: { transactions: RawShortcutTransaction[] } = await triggerShortcutRequest(hooksApiUrl, { address: walletAddress, @@ -112,39 +116,43 @@ export async function prepareWithdrawAndClaimTransactions({ tokens: [ { tokenId: dataProps.withdrawTokenId, - amount: useMax ? balance : amount, - useMax, + amount: balance, + useMax: true, }, ], ...shortcutTriggerArgs?.withdraw, }) - const claimTransactions = await Promise.all( - rewardsPositions.map(async (position): Promise => { - const { transactions }: { transactions: RawShortcutTransaction[] } = - await triggerShortcutRequest(hooksApiUrl, { - address: walletAddress, - appId, - networkId, - shortcutId: 'claim-rewards', - ...position.shortcutTriggerArgs?.['claim-rewards'], + + // Prepare the claim transactions if there are rewards positions + const claimTransactions = rewardsPositions + ? await Promise.all( + rewardsPositions.map(async (position): Promise => { + const { transactions }: { transactions?: RawShortcutTransaction[] } = + await triggerShortcutRequest(hooksApiUrl, { + address: walletAddress, + appId, + networkId, + shortcutId: 'claim-rewards', + ...position.shortcutTriggerArgs?.['claim-rewards'], + }) + return transactions ?? [] // Default to an empty array if rewardsPositions is undefined }) - return transactions - }) - ) - Logger.debug(TAG, 'prepareWithdrawAndClaimTransactions', { - withdrawTransactions, - claimTransactions, - pool, - }) - return prepareTransactions({ - feeCurrencies, - baseTransactions: rawShortcutTransactionsToTransactionRequests([ - ...withdrawTransactions, - ..._.flatten(claimTransactions), - ]), - isGasSubsidized: isGasSubsidizedForNetwork(pool.networkId), - origin: 'earn-withdraw', - }) + ) + : [] + + return { + prepareTransactionsResult: await prepareTransactions({ + feeCurrencies, + baseTransactions: rawShortcutTransactionsToTransactionRequests([ + ...withdrawTransactions, + ...claimTransactions.flat(), + ]), + spendToken: token, + spendTokenAmount: new BigNumber(balance).shiftedBy(token.decimals), + isGasSubsidized: isGasSubsidizedForNetwork(networkId), + origin: 'earn-withdraw', + }), + } } export async function prepareWithdrawTransactions({ @@ -154,7 +162,6 @@ export async function prepareWithdrawTransactions({ feeCurrencies, pool, hooksApiUrl, - shortcutId, useMax, }: { amount: string @@ -166,22 +173,22 @@ export async function prepareWithdrawTransactions({ shortcutId: Exclude useMax: boolean }) { - const { dataProps } = pool + const { appId, balance, dataProps, networkId, shortcutTriggerArgs } = pool const { transactions }: { transactions: RawShortcutTransaction[] } = await triggerShortcutRequest( hooksApiUrl, { address: walletAddress, - appId: pool.appId, - networkId: pool.networkId, - shortcutId, + appId, + networkId, + shortcutId: 'withdraw', tokens: [ { tokenId: dataProps.withdrawTokenId, - amount, + amount: useMax ? balance : amount, useMax, }, ], - ...pool.shortcutTriggerArgs?.[shortcutId], + ...shortcutTriggerArgs?.withdraw, } ) @@ -189,29 +196,56 @@ export async function prepareWithdrawTransactions({ prepareTransactionsResult: await prepareTransactions({ feeCurrencies, baseTransactions: rawShortcutTransactionsToTransactionRequests(transactions), - isGasSubsidized: isGasSubsidizedForNetwork(token.networkId), - origin: `earn-${shortcutId}`, + spendToken: token, + spendTokenAmount: new BigNumber(amount).shiftedBy(token.decimals), + isGasSubsidized: isGasSubsidizedForNetwork(networkId), + origin: 'earn-withdraw', }), - swapTransaction: undefined, } } -export function usePrepareTransactions(mode: EarnActiveAction) { - const prepareTransactions = useAsyncCallback( - mode === 'withdraw' ? prepareWithdrawTransactions : prepareDepositTransactions, - { - onError: (err) => { - const error = ensureError(err) - Logger.error(TAG, 'usePrepareWithdrawTransactions', error) - }, - } - ) +export async function prepareClaimTransactions({ + pool, + walletAddress, + feeCurrencies, + hooksApiUrl, + rewardsPositions, +}: { + pool: EarnPosition + walletAddress: Address + feeCurrencies: TokenBalance[] + hooksApiUrl: string + rewardsPositions: Position[] +}) { + const { appId, networkId } = pool + // Prepare the claim transactions if there are rewards positions + const claimTransactions = rewardsPositions + ? await Promise.all( + rewardsPositions.map(async (position): Promise => { + const { transactions }: { transactions?: RawShortcutTransaction[] } = + await triggerShortcutRequest(hooksApiUrl, { + address: walletAddress, + appId, + networkId, + shortcutId: 'claim-rewards', + ...position.shortcutTriggerArgs?.['claim-rewards'], + }) + return transactions ?? [] // Default to an empty array if rewardsPositions is undefined + }) + ) + : [] + + Logger.debug(TAG, 'prepareClaimTransactions', { + claimTransactions, + pool, + }) return { - prepareTransactionsResult: prepareTransactions.result, - refreshPreparedTransactions: prepareTransactions.execute, - clearPreparedTransactions: prepareTransactions.reset, - prepareTransactionError: prepareTransactions.error, - isPreparingTransactions: prepareTransactions.loading, + prepareTransactionsResult: await prepareTransactions({ + feeCurrencies, + baseTransactions: rawShortcutTransactionsToTransactionRequests(claimTransactions.flat()), + isGasSubsidized: isGasSubsidizedForNetwork(networkId), + origin: 'earn-claim-rewards', + }), } } From e9f2c075215324c83c03db3c107e9b1a62df6523 Mon Sep 17 00:00:00 2001 From: Tom McGuire Date: Fri, 25 Oct 2024 13:57:17 -0700 Subject: [PATCH 2/8] fix(earn): check rewardsPositions length --- src/earn/prepareTransactions.ts | 62 +++++++++++++++++---------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/earn/prepareTransactions.ts b/src/earn/prepareTransactions.ts index 5cc6d99ac8c..2b925989c2f 100644 --- a/src/earn/prepareTransactions.ts +++ b/src/earn/prepareTransactions.ts @@ -124,21 +124,22 @@ export async function prepareWithdrawAndClaimTransactions({ }) // Prepare the claim transactions if there are rewards positions - const claimTransactions = rewardsPositions - ? await Promise.all( - rewardsPositions.map(async (position): Promise => { - const { transactions }: { transactions?: RawShortcutTransaction[] } = - await triggerShortcutRequest(hooksApiUrl, { - address: walletAddress, - appId, - networkId, - shortcutId: 'claim-rewards', - ...position.shortcutTriggerArgs?.['claim-rewards'], - }) - return transactions ?? [] // Default to an empty array if rewardsPositions is undefined - }) - ) - : [] + const claimTransactions = + rewardsPositions && rewardsPositions.length > 0 + ? await Promise.all( + rewardsPositions.map(async (position): Promise => { + const { transactions }: { transactions?: RawShortcutTransaction[] } = + await triggerShortcutRequest(hooksApiUrl, { + address: walletAddress, + appId, + networkId, + shortcutId: 'claim-rewards', + ...position.shortcutTriggerArgs?.['claim-rewards'], + }) + return transactions ?? [] // Default to an empty array if rewardsPositions is undefined + }) + ) + : [] return { prepareTransactionsResult: await prepareTransactions({ @@ -220,21 +221,22 @@ export async function prepareClaimTransactions({ const { appId, networkId } = pool // Prepare the claim transactions if there are rewards positions - const claimTransactions = rewardsPositions - ? await Promise.all( - rewardsPositions.map(async (position): Promise => { - const { transactions }: { transactions?: RawShortcutTransaction[] } = - await triggerShortcutRequest(hooksApiUrl, { - address: walletAddress, - appId, - networkId, - shortcutId: 'claim-rewards', - ...position.shortcutTriggerArgs?.['claim-rewards'], - }) - return transactions ?? [] // Default to an empty array if rewardsPositions is undefined - }) - ) - : [] + const claimTransactions = + rewardsPositions.length > 0 + ? await Promise.all( + rewardsPositions.map(async (position): Promise => { + const { transactions }: { transactions?: RawShortcutTransaction[] } = + await triggerShortcutRequest(hooksApiUrl, { + address: walletAddress, + appId, + networkId, + shortcutId: 'claim-rewards', + ...position.shortcutTriggerArgs?.['claim-rewards'], + }) + return transactions ?? [] // Default to an empty array if rewardsPositions is undefined + }) + ) + : [] Logger.debug(TAG, 'prepareClaimTransactions', { claimTransactions, From 98a8bd00d6a0d1ecef892ad8d7bdc34d39e86b63 Mon Sep 17 00:00:00 2001 From: Tom McGuire Date: Fri, 25 Oct 2024 14:06:15 -0700 Subject: [PATCH 3/8] fix(earn): remove conditional shortcutId assignment based on mode --- src/earn/EarnConfirmationScreen.tsx | 3 +-- src/earn/EarnEnterAmount.tsx | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/earn/EarnConfirmationScreen.tsx b/src/earn/EarnConfirmationScreen.tsx index 619980dd06e..e26ff0666d9 100644 --- a/src/earn/EarnConfirmationScreen.tsx +++ b/src/earn/EarnConfirmationScreen.tsx @@ -104,8 +104,7 @@ export default function EarnConfirmationScreen({ route }: Props) { feeCurrencies, pool, hooksApiUrl, - // Mode === shortcutId, except for exit which is withdraw - shortcutId: mode === 'exit' ? 'withdraw' : mode, + shortcutId: mode, useMax, }) } diff --git a/src/earn/EarnEnterAmount.tsx b/src/earn/EarnEnterAmount.tsx index 104c51d3b30..a209e208c75 100644 --- a/src/earn/EarnEnterAmount.tsx +++ b/src/earn/EarnEnterAmount.tsx @@ -171,8 +171,7 @@ function EarnEnterAmount({ route }: Props) { feeCurrencies, pool, hooksApiUrl, - // Mode === shortcutId, except for exit which is withdraw - shortcutId: mode === 'exit' ? 'withdraw' : mode, + shortcutId: mode, useMax: maxPressed, }) } From f1ac2db1493e21eb57a8477ad2dcb91408896a01 Mon Sep 17 00:00:00 2001 From: Tom McGuire Date: Fri, 25 Oct 2024 14:06:57 -0700 Subject: [PATCH 4/8] fix(earn): make rewardsPositions type optional --- src/earn/prepareTransactions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/earn/prepareTransactions.ts b/src/earn/prepareTransactions.ts index 2b925989c2f..7ac8e2dad91 100644 --- a/src/earn/prepareTransactions.ts +++ b/src/earn/prepareTransactions.ts @@ -216,13 +216,13 @@ export async function prepareClaimTransactions({ walletAddress: Address feeCurrencies: TokenBalance[] hooksApiUrl: string - rewardsPositions: Position[] + rewardsPositions?: Position[] }) { const { appId, networkId } = pool // Prepare the claim transactions if there are rewards positions const claimTransactions = - rewardsPositions.length > 0 + rewardsPositions && rewardsPositions.length > 0 ? await Promise.all( rewardsPositions.map(async (position): Promise => { const { transactions }: { transactions?: RawShortcutTransaction[] } = From 37dd5bb44cdfdc9c9ba07a3fd6bf3b27ded71b60 Mon Sep 17 00:00:00 2001 From: Tom McGuire Date: Fri, 25 Oct 2024 14:29:56 -0700 Subject: [PATCH 5/8] chore(earn): remove unused PrepareWithdrawAndClaimParams --- src/earn/types.ts | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/earn/types.ts b/src/earn/types.ts index b74922282c1..621b94262d6 100644 --- a/src/earn/types.ts +++ b/src/earn/types.ts @@ -1,9 +1,8 @@ -import { EarnPosition, Position, Token } from 'src/positions/types' +import { EarnPosition, Token } from 'src/positions/types' import Colors from 'src/styles/colors' -import { TokenBalance } from 'src/tokens/slice' import { NetworkId } from 'src/transactions/types' import { SerializableTransactionRequest } from 'src/viem/preparedTransactionSerialization' -import { Address, Hash } from 'viem' +import { Hash } from 'viem' export interface DepositInfo { amount: string @@ -41,16 +40,6 @@ export interface PoolInfo { apy: number } -export interface PrepareWithdrawAndClaimParams { - pool: EarnPosition - walletAddress: Address - feeCurrencies: TokenBalance[] - hooksApiUrl: string - rewardsPositions: Position[] - amount?: string - useMax?: boolean -} - export type BeforeDepositActionName = | 'Add' | 'Transfer' From 34379cf203021ea88225c7efcf6871c06313ddc8 Mon Sep 17 00:00:00 2001 From: Tom McGuire Date: Fri, 25 Oct 2024 15:17:47 -0700 Subject: [PATCH 6/8] fix(earn-confirmation): remove unused swap transaction --- src/earn/EarnConfirmationScreen.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/earn/EarnConfirmationScreen.tsx b/src/earn/EarnConfirmationScreen.tsx index e26ff0666d9..dfb597665e1 100644 --- a/src/earn/EarnConfirmationScreen.tsx +++ b/src/earn/EarnConfirmationScreen.tsx @@ -79,8 +79,7 @@ export default function EarnConfirmationScreen({ route }: Props) { ) const { - // @ts-expect-error prepareTransactionsResult & swapTransaction are only set when mode === 'deposit' or 'swap-deposit' - prepareTransactionsResult: { prepareTransactionsResult, swapTransaction } = {}, + prepareTransactionsResult: { prepareTransactionsResult } = {}, refreshPreparedTransactions, clearPreparedTransactions, prepareTransactionError, From 9f2d5301ee2e1aafce25be7e5a14a34f9787a94c Mon Sep 17 00:00:00 2001 From: Tom McGuire Date: Fri, 25 Oct 2024 15:18:53 -0700 Subject: [PATCH 7/8] docs(earn-enter-amount): update ts-expect-error expect error --- src/earn/EarnEnterAmount.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/earn/EarnEnterAmount.tsx b/src/earn/EarnEnterAmount.tsx index a209e208c75..2d45561f4c8 100644 --- a/src/earn/EarnEnterAmount.tsx +++ b/src/earn/EarnEnterAmount.tsx @@ -144,7 +144,7 @@ function EarnEnterAmount({ route }: Props) { } const { - // @ts-expect-error prepareTransactionsResult & swapTransaction are only set when mode === 'deposit' or 'swap-deposit' + // @ts-expect-error swapTransaction only exists on swap-deposit mode prepareTransactionsResult: { prepareTransactionsResult, swapTransaction } = {}, refreshPreparedTransactions, clearPreparedTransactions, From 5a1af5d6c0b58e3882d999e74f439c5ede09f2c1 Mon Sep 17 00:00:00 2001 From: Tom McGuire Date: Fri, 25 Oct 2024 17:23:00 -0700 Subject: [PATCH 8/8] fix(earn): add args to usePrepareTransactions for claim --- src/earn/EarnConfirmationScreen.tsx | 2 +- src/earn/hooks.ts | 14 +++++-- src/earn/prepareTransactions.ts | 62 +++++++++++++---------------- 3 files changed, 40 insertions(+), 38 deletions(-) diff --git a/src/earn/EarnConfirmationScreen.tsx b/src/earn/EarnConfirmationScreen.tsx index dfb597665e1..1967c2d7aa9 100644 --- a/src/earn/EarnConfirmationScreen.tsx +++ b/src/earn/EarnConfirmationScreen.tsx @@ -84,7 +84,7 @@ export default function EarnConfirmationScreen({ route }: Props) { clearPreparedTransactions, prepareTransactionError, isPreparingTransactions, - } = usePrepareTransactions(mode) + } = usePrepareTransactions(mode, { rewardsPositions }) const handleRefreshPreparedTransactions = ( amount: BigNumber, diff --git a/src/earn/hooks.ts b/src/earn/hooks.ts index b56cf9b5372..ec16bad72e1 100644 --- a/src/earn/hooks.ts +++ b/src/earn/hooks.ts @@ -11,7 +11,7 @@ import { fetchExchanges } from 'src/fiatExchanges/utils' import { isAppSwapsEnabledSelector } from 'src/navigator/selectors' import { userLocationDataSelector } from 'src/networkInfo/selectors' import { earnPositionsSelector } from 'src/positions/selectors' -import { EarnPosition } from 'src/positions/types' +import { EarnPosition, Position } from 'src/positions/types' import { useSelector } from 'src/redux/hooks' import { getFeatureGate } from 'src/statsig' import { StatsigFeatureGates } from 'src/statsig/types' @@ -91,7 +91,10 @@ export function useDepositEntrypointInfo({ return { hasDepositToken, hasTokensOnSameNetwork, hasTokensOnOtherNetworks, canCashIn, exchanges } } -export function usePrepareTransactions(mode: EarnActiveAction) { +export function usePrepareTransactions( + mode: EarnActiveAction, + additionalArgs?: { rewardsPositions: Position[] } +) { const getTransactionFunction = () => { switch (mode) { case 'deposit': @@ -110,10 +113,15 @@ export function usePrepareTransactions(mode: EarnActiveAction) { const prepareTransactions = useAsyncCallback( async (args) => { + const modifiedArgs = { ...args } + // Add rewardsPositions passed to usePrepareTransactions if the mode is 'exit' or 'claim-rewards' + if (mode === 'exit' || mode === 'claim-rewards') { + modifiedArgs.rewardsPositions = additionalArgs?.rewardsPositions + } // Get the appropriate function based on the mode const prepareFunction = getTransactionFunction() // Ensure the function is called with the necessary arguments - return prepareFunction(args) + return prepareFunction(modifiedArgs) }, { onError: (err) => { diff --git a/src/earn/prepareTransactions.ts b/src/earn/prepareTransactions.ts index 7ac8e2dad91..c720839d183 100644 --- a/src/earn/prepareTransactions.ts +++ b/src/earn/prepareTransactions.ts @@ -104,7 +104,7 @@ export async function prepareWithdrawAndClaimTransactions({ feeCurrencies: TokenBalance[] pool: EarnPosition hooksApiUrl: string - rewardsPositions?: Position[] + rewardsPositions: Position[] }) { const { appId, balance, dataProps, networkId, shortcutTriggerArgs } = pool const { transactions: withdrawTransactions }: { transactions: RawShortcutTransaction[] } = @@ -124,22 +124,19 @@ export async function prepareWithdrawAndClaimTransactions({ }) // Prepare the claim transactions if there are rewards positions - const claimTransactions = - rewardsPositions && rewardsPositions.length > 0 - ? await Promise.all( - rewardsPositions.map(async (position): Promise => { - const { transactions }: { transactions?: RawShortcutTransaction[] } = - await triggerShortcutRequest(hooksApiUrl, { - address: walletAddress, - appId, - networkId, - shortcutId: 'claim-rewards', - ...position.shortcutTriggerArgs?.['claim-rewards'], - }) - return transactions ?? [] // Default to an empty array if rewardsPositions is undefined - }) - ) - : [] + const claimTransactions = await Promise.all( + rewardsPositions.map(async (position): Promise => { + const { transactions }: { transactions?: RawShortcutTransaction[] } = + await triggerShortcutRequest(hooksApiUrl, { + address: walletAddress, + appId, + networkId, + shortcutId: 'claim-rewards', + ...position.shortcutTriggerArgs?.['claim-rewards'], + }) + return transactions ?? [] // Default to an empty array if rewardsPositions is undefined + }) + ) return { prepareTransactionsResult: await prepareTransactions({ @@ -216,27 +213,24 @@ export async function prepareClaimTransactions({ walletAddress: Address feeCurrencies: TokenBalance[] hooksApiUrl: string - rewardsPositions?: Position[] + rewardsPositions: Position[] }) { const { appId, networkId } = pool // Prepare the claim transactions if there are rewards positions - const claimTransactions = - rewardsPositions && rewardsPositions.length > 0 - ? await Promise.all( - rewardsPositions.map(async (position): Promise => { - const { transactions }: { transactions?: RawShortcutTransaction[] } = - await triggerShortcutRequest(hooksApiUrl, { - address: walletAddress, - appId, - networkId, - shortcutId: 'claim-rewards', - ...position.shortcutTriggerArgs?.['claim-rewards'], - }) - return transactions ?? [] // Default to an empty array if rewardsPositions is undefined - }) - ) - : [] + const claimTransactions = await Promise.all( + rewardsPositions.map(async (position): Promise => { + const { transactions }: { transactions?: RawShortcutTransaction[] } = + await triggerShortcutRequest(hooksApiUrl, { + address: walletAddress, + appId, + networkId, + shortcutId: 'claim-rewards', + ...position.shortcutTriggerArgs?.['claim-rewards'], + }) + return transactions ?? [] // Default to an empty array if rewardsPositions is undefined + }) + ) Logger.debug(TAG, 'prepareClaimTransactions', { claimTransactions,