diff --git a/src/components/scenes/Staking/EarnScene.tsx b/src/components/scenes/Staking/EarnScene.tsx index a1fcf032b50..87b82a1309e 100644 --- a/src/components/scenes/Staking/EarnScene.tsx +++ b/src/components/scenes/Staking/EarnScene.tsx @@ -25,6 +25,9 @@ import { cacheStyles, Theme, useTheme } from '../../services/ThemeContext' interface Props extends EdgeAppSceneProps<'earnScene'> {} +let USERNAME: string | undefined +let STAKE_POLICY_MAP: StakePolicyMap = {} + export interface EarnSceneParams {} interface WalletStakeInfo { @@ -49,6 +52,11 @@ export const EarnScene = (props: Props) => { const styles = getStyles(theme) const account = useSelector(state => state.core.account) + if (USERNAME !== account.username) { + // Reset local variable if user changes + USERNAME = account.username + STAKE_POLICY_MAP = {} + } const currencyConfigMap = useSelector(state => state.core.account.currencyConfig) @@ -58,11 +66,7 @@ export const EarnScene = (props: Props) => { const [isPortfolioSelected, setIsPortfolioSelected] = React.useState(false) const [isLoading, setIsLoading] = React.useState(true) - // Store `stakePolicyMap` in a ref and manage re-renders manually to avoid - // re-initializing it every time we enter the scene. const [updateCounter, setUpdateCounter] = React.useState(0) - const stakePolicyMapRef = React.useRef({}) - const stakePolicyMap = stakePolicyMapRef.current const handleSelectEarn = useHandler(() => setIsPortfolioSelected(false)) const handleSelectPortfolio = useHandler(() => setIsPortfolioSelected(true)) @@ -71,20 +75,20 @@ export const EarnScene = (props: Props) => { async () => { for (const pluginId of Object.keys(currencyConfigMap)) { const isStakingSupported = SPECIAL_CURRENCY_INFO[pluginId]?.isStakingSupported === true && ENV.ENABLE_STAKING - if (stakePolicyMap[pluginId] != null || !isStakingSupported) continue + if (STAKE_POLICY_MAP[pluginId] != null || !isStakingSupported) continue // Initialize stake policy - try { - const stakePlugins = await getStakePlugins(pluginId) - stakePolicyMap[pluginId] = [] + const stakePlugins = await getStakePlugins(pluginId) + STAKE_POLICY_MAP[pluginId] = [] - for (const stakePlugin of stakePlugins) { - const stakePolicies = stakePlugin.getPolicies({ currencyCode: currencyConfigMap[pluginId].currencyInfo.currencyCode }) - const matchingWallets = wallets.filter((wallet: EdgeCurrencyWallet) => wallet.currencyInfo.pluginId === pluginId) + const matchingWallets = wallets.filter((wallet: EdgeCurrencyWallet) => wallet.currencyInfo.pluginId === pluginId) + for (const stakePlugin of stakePlugins) { + const stakePolicies = stakePlugin.getPolicies({ pluginId }) - for (const stakePolicy of stakePolicies) { - const walletStakePositions = [] - for (const wallet of matchingWallets) { + for (const stakePolicy of stakePolicies) { + const walletStakePositions = [] + for (const wallet of matchingWallets) { + try { // Determine if a wallet matching this policy has an open position const stakePosition = await stakePlugin.fetchStakePosition({ stakePolicyId: stakePolicy.stakePolicyId, wallet, account }) const allocations = getPositionAllocations(stakePosition) @@ -92,19 +96,19 @@ export const EarnScene = (props: Props) => { const isPositionOpen = [...staked, ...earned, ...unstaked].some(positionAllocation => !zeroString(positionAllocation.nativeAmount)) walletStakePositions.push({ wallet, isPositionOpen, stakePosition }) + } catch (e) { + showDevError(e) } - - stakePolicyMap[pluginId].push({ - stakePlugin, - stakePolicy, - walletStakeInfos: walletStakePositions - }) - // Trigger re-render - setUpdateCounter(prevCounter => prevCounter + 1) } + + STAKE_POLICY_MAP[pluginId].push({ + stakePlugin, + stakePolicy, + walletStakeInfos: walletStakePositions + }) + // Trigger re-render + setUpdateCounter(prevCounter => prevCounter + 1) } - } catch (e) { - showDevError(e) } } setIsLoading(false) @@ -116,12 +120,16 @@ export const EarnScene = (props: Props) => { const renderStakeItems = (displayStakeInfo: DisplayStakeInfo, currencyInfo: EdgeCurrencyInfo) => { const { stakePlugin, stakePolicy, walletStakeInfos } = displayStakeInfo + const openStakePositions = walletStakeInfos.filter(walletStakeInfo => walletStakeInfo.isPositionOpen) + + if (isPortfolioSelected && openStakePositions.length === 0) { + return null + } + const handlePress = async () => { let walletId: string | undefined let stakePosition - const openStakePositions = walletStakeInfos.filter(walletStakeInfo => walletStakeInfo.isPositionOpen) - if (walletStakeInfos.length === 1 || (isPortfolioSelected && openStakePositions.length === 1)) { // Only one compatible wallet if on "Discover", or only one open // position on "Portfolio." Auto-select the wallet. @@ -179,8 +187,8 @@ export const EarnScene = (props: Props) => { - {Object.keys(stakePolicyMap).map(pluginId => - stakePolicyMap[pluginId].map(displayStakeInfo => renderStakeItems(displayStakeInfo, currencyConfigMap[pluginId].currencyInfo)) + {Object.keys(STAKE_POLICY_MAP).map(pluginId => + STAKE_POLICY_MAP[pluginId].map(displayStakeInfo => renderStakeItems(displayStakeInfo, currencyConfigMap[pluginId].currencyInfo)) )} {isLoading && } diff --git a/src/components/scenes/Staking/StakeOptionsScene.tsx b/src/components/scenes/Staking/StakeOptionsScene.tsx index f53b9fa2402..17572401a58 100644 --- a/src/components/scenes/Staking/StakeOptionsScene.tsx +++ b/src/components/scenes/Staking/StakeOptionsScene.tsx @@ -64,7 +64,7 @@ const StakeOptionsSceneComponent = (props: Props) => { const handleStakeOptionPress = (stakePolicy: StakePolicy) => { const { stakePolicyId } = stakePolicy - const stakePlugin = getPluginFromPolicy(stakePlugins, stakePolicy) + const stakePlugin = getPluginFromPolicy(stakePlugins, stakePolicy, { pluginId }) // Transition to next scene immediately const stakePosition = stakePositionMap[stakePolicyId] if (stakePlugin != null) navigation.push('stakeOverview', { stakePlugin, walletId: wallet.id, stakePolicy: stakePolicy, stakePosition }) diff --git a/src/components/themed/TransactionListTop.tsx b/src/components/themed/TransactionListTop.tsx index ef8ae6c391c..66a3000d0d0 100644 --- a/src/components/themed/TransactionListTop.tsx +++ b/src/components/themed/TransactionListTop.tsx @@ -153,7 +153,7 @@ export class TransactionListTopComponent extends React.PureComponent { let lockedNativeAmount = '0' const stakePositionMap: StakePositionMap = {} - for (const stakePolicy of stakePolicies) { - // Don't show liquid staking positions as locked amount - if (stakePolicy.isLiquidStaking === true) continue - - let total: string | undefined - const stakePlugin = getPluginFromPolicy(stakePlugins, stakePolicy) - if (stakePlugin == null) continue - try { - const stakePosition = await stakePlugin.fetchStakePosition({ - stakePolicyId: stakePolicy.stakePolicyId, - wallet: this.props.wallet, - account: this.props.account - }) + for (const stakePlugin of stakePlugins) { + for (const stakePolicy of stakePolicies) { + // Don't show liquid staking positions as locked amount + if (stakePolicy.isLiquidStaking === true) continue + + let total: string | undefined + try { + const stakePosition = await stakePlugin.fetchStakePosition({ + stakePolicyId: stakePolicy.stakePolicyId, + wallet: this.props.wallet, + account: this.props.account + }) - stakePositionMap[stakePolicy.stakePolicyId] = stakePosition - const { staked, earned } = getPositionAllocations(stakePosition) - total = this.getTotalPosition(this.props.currencyCode, [...staked, ...earned]) - } catch (err) { - console.error(err) - const { displayName } = stakePolicy.stakeProviderInfo - datelog(`${displayName}: ${lstrings.stake_unable_to_query_locked}`) - continue - } + stakePositionMap[stakePolicy.stakePolicyId] = stakePosition + const { staked, earned } = getPositionAllocations(stakePosition) + total = this.getTotalPosition(this.props.currencyCode, [...staked, ...earned]) + } catch (err) { + console.error(err) + const { displayName } = stakePolicy.stakeProviderInfo + datelog(`${displayName}: ${lstrings.stake_unable_to_query_locked}`) + continue + } - lockedNativeAmount = add(lockedNativeAmount, total) + lockedNativeAmount = add(lockedNativeAmount, total) + } } this.setState({ stakePositionMap }) this.setState({ lockedNativeAmount }) @@ -641,7 +641,7 @@ export class TransactionListTopComponent extends React.PureComponent - [...policy.rewardAssets, ...policy.stakeAssets].some(asset => asset.pluginId === wallet.currencyInfo.pluginId) - ) - } - if (currencyCode != null) { - filteredPolicies = filteredPolicies.filter(policy => - [...policy.rewardAssets, ...policy.stakeAssets].some(asset => asset.currencyCode === currencyCode) - ) - } - - return filteredPolicies + return filterStakePolicies(policies, filter) }, async fetchChangeQuote(request: ChangeQuoteRequest): Promise { diff --git a/src/plugins/stake-plugins/generic/policyAdapters/EthereumKilnAdaptor.ts b/src/plugins/stake-plugins/generic/policyAdapters/EthereumKilnAdaptor.ts index 6494d314b17..545dfaf91dc 100644 --- a/src/plugins/stake-plugins/generic/policyAdapters/EthereumKilnAdaptor.ts +++ b/src/plugins/stake-plugins/generic/policyAdapters/EthereumKilnAdaptor.ts @@ -68,8 +68,13 @@ export const makeEthereumKilnAdapter = (policyConfig: StakePolicyConfig txCount++ + let txCount: number | undefined + const nextNonce = async (): Promise => { + if (txCount == null) { + txCount = await walletSigner.getTransactionCount('pending') + } + return txCount++ + } const feeData = await provider.getFeeData() const maxFeePerGas = feeData.maxFeePerGas !== null ? feeData.maxFeePerGas : undefined @@ -113,7 +118,7 @@ export const makeEthereumKilnAdapter = (policyConfig: StakePolicyConfig txCount++ + let txCount: number | undefined + const nextNonce = async (): Promise => { + if (txCount == null) { + txCount = await walletSigner.getTransactionCount('pending') + } + return txCount++ + } const feeData = await provider.getFeeData() const maxFeePerGas = feeData.maxFeePerGas !== null ? feeData.maxFeePerGas : undefined @@ -109,7 +114,7 @@ export const makeGlifInfinityPoolAdapter = (policyConfig: StakePolicyConfig [...policy.rewardAssets, ...policy.stakeAssets].some(asset => asset.pluginId === wallet.currencyInfo.pluginId)) @@ -199,6 +200,9 @@ export const filterStakePolicies = (policies: StakePolicy[], filter?: StakePolic if (currencyCode != null) { out = out.filter(policy => [...policy.rewardAssets, ...policy.stakeAssets].some(asset => asset.currencyCode === currencyCode)) } + if (pluginId != null) { + out = out.filter(policy => [...policy.rewardAssets, ...policy.stakeAssets].some(asset => asset.pluginId === pluginId)) + } return out } diff --git a/src/plugins/stake-plugins/uniswapV2/uniV2Plugin.ts b/src/plugins/stake-plugins/uniswapV2/uniV2Plugin.ts index 0905f2e511d..b1dbd355e4c 100644 --- a/src/plugins/stake-plugins/uniswapV2/uniV2Plugin.ts +++ b/src/plugins/stake-plugins/uniswapV2/uniV2Plugin.ts @@ -13,10 +13,10 @@ export const makeUniV2StakePlugin = async (pluginId: string): Promise [...policy.rewardAssets, ...policy.stakeAssets].some(asset => asset.pluginId === wallet.currencyInfo.pluginId)) + if (pluginId != null) { + out = out.filter(policy => [...policy.rewardAssets, ...policy.stakeAssets].some(asset => asset.pluginId === pluginId)) } if (currencyCode != null) { out = out.filter(policy => [...policy.rewardAssets, ...policy.stakeAssets].some(asset => asset.currencyCode === currencyCode)) diff --git a/src/util/stakeUtils.ts b/src/util/stakeUtils.ts index a723c8033d9..78b851b2163 100644 --- a/src/util/stakeUtils.ts +++ b/src/util/stakeUtils.ts @@ -4,7 +4,7 @@ import { sprintf } from 'sprintf-js' import { formatTimeDate } from '../locales/intl' import { lstrings } from '../locales/strings' -import { PositionAllocation, StakePlugin, StakePolicy, StakePosition } from '../plugins/stake-plugins/types' +import { PositionAllocation, StakePlugin, StakePolicy, StakePolicyFilter, StakePosition } from '../plugins/stake-plugins/types' import { getCurrencyIconUris } from './CdnUris' import { getUkCompliantString } from './ukComplianceUtils' @@ -88,8 +88,8 @@ export const getPolicyIconUris = ( return { stakeAssetUris, rewardAssetUris } } -export const getPluginFromPolicy = (stakePlugins: StakePlugin[], stakePolicy: StakePolicy): StakePlugin | undefined => { - return stakePlugins.find(plugin => plugin.getPolicies().find(policy => policy.stakePolicyId === stakePolicy.stakePolicyId)) +export const getPluginFromPolicy = (stakePlugins: StakePlugin[], stakePolicy: StakePolicy, filter?: StakePolicyFilter): StakePlugin | undefined => { + return stakePlugins.find(plugin => plugin.getPolicies(filter).find(policy => policy.stakePolicyId === stakePolicy.stakePolicyId)) } /**