From 5f51bb5b29d1c5d5ba37ba3d2dfb3b5fe9ab5a2a Mon Sep 17 00:00:00 2001 From: Atatakai Date: Thu, 19 Dec 2024 20:30:25 +0400 Subject: [PATCH 1/2] feat: support additional tokens required for initial funding --- electron/store.js | 1 + .../AlertSections/LowFunds/EmptyFunds.tsx | 2 +- .../LowFunds/FundsToActivate.tsx | 33 +++++- .../AlertSections/LowFunds/LowFunds.tsx | 17 +-- .../AlertSections/LowFunds/MainNeedsFunds.tsx | 6 +- .../AlertSections/NewStakingProgramAlert.tsx | 20 ++-- .../MainPage/sections/AlertSections/index.tsx | 3 +- .../SetupPage/Create/SetupEoaFunding.tsx | 5 +- frontend/config/agents.ts | 15 ++- frontend/config/tokens.ts | 11 ++ frontend/constants/serviceTemplates.ts | 6 +- frontend/context/BalanceProvider.tsx | 7 +- frontend/enums/Agent.ts | 2 +- frontend/hooks/useNeedsFunds.ts | 104 ++++++++++++------ frontend/types/Agent.ts | 3 + frontend/types/ElectronApi.ts | 1 + 16 files changed, 159 insertions(+), 77 deletions(-) diff --git a/electron/store.js b/electron/store.js index 215b6c097..21a3f0334 100644 --- a/electron/store.js +++ b/electron/store.js @@ -13,6 +13,7 @@ const schema = { lastSelectedAgentType: { type: 'string', default: 'trader' }, isInitialFunded_trader: { type: 'boolean', default: false }, isInitialFunded_memeooorr: { type: 'boolean', default: false }, + isInitialFunded_modius: { type: 'boolean', default: false }, }; /** diff --git a/frontend/components/MainPage/sections/AlertSections/LowFunds/EmptyFunds.tsx b/frontend/components/MainPage/sections/AlertSections/LowFunds/EmptyFunds.tsx index a98695ecc..b32f59633 100644 --- a/frontend/components/MainPage/sections/AlertSections/LowFunds/EmptyFunds.tsx +++ b/frontend/components/MainPage/sections/AlertSections/LowFunds/EmptyFunds.tsx @@ -43,7 +43,7 @@ export const EmptyFunds = () => { )} - + } type="primary" diff --git a/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx b/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx index fd7db6a63..85534c651 100644 --- a/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx +++ b/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx @@ -16,17 +16,20 @@ const { Text } = Typography; type FundsToActivateProps = { stakingFundsRequired: boolean; - otherFundsRequired: boolean; + nativeFundsRequired: boolean; + additionalFundsRequired?: boolean; }; const FUNDS_REQUIRED_FOR_BY_AGENT_TYPE = { [AgentType.PredictTrader]: 'for trading', [AgentType.Memeooorr]: 'for agent operations', + [AgentType.Modius]: 'minimum for investment', }; export const FundsToActivate = ({ stakingFundsRequired = true, - otherFundsRequired = true, + nativeFundsRequired = true, + additionalFundsRequired = true, }: FundsToActivateProps) => { const { selectedStakingProgramId } = useStakingProgram(); @@ -49,6 +52,22 @@ export const FundsToActivate = ({ return `${native} ${nativeTokenSymbol}`; }, [homeChainId, serviceFundRequirements, nativeTokenSymbol]); + // Calculate additional tokens requirements (Eg. USDC) + const additionalTokensRequired = useMemo(() => { + const additionalTokens = Object.keys( + serviceFundRequirements[homeChainId], + ).filter( + (token) => token !== TokenSymbol.OLAS && token !== nativeTokenSymbol, + ); + + if (additionalTokens.length === 0) []; + + return additionalTokens.map((tokenSymbol) => { + const token = serviceFundRequirements[homeChainId][tokenSymbol]; + return `${token} ${tokenSymbol}`; + }); + }, [homeChainId, serviceFundRequirements, nativeTokenSymbol]); + return ( <> @@ -63,12 +82,20 @@ export const FundsToActivate = ({ staking. )} - {otherFundsRequired && ( + {nativeFundsRequired && (
{UNICODE_SYMBOLS.BULLET} {nativeTokenRequired} - {` ${FUNDS_REQUIRED_FOR_BY_AGENT_TYPE[selectedAgentType]}.`}
)} + + {additionalFundsRequired && + additionalTokensRequired.map((additionalToken) => ( +
+ {UNICODE_SYMBOLS.BULLET} {additionalToken} - + {` ${FUNDS_REQUIRED_FOR_BY_AGENT_TYPE[selectedAgentType]}.`} +
+ ))} {masterSafeAddress && ( diff --git a/frontend/components/MainPage/sections/AlertSections/LowFunds/LowFunds.tsx b/frontend/components/MainPage/sections/AlertSections/LowFunds/LowFunds.tsx index d0fb2525c..744e4db34 100644 --- a/frontend/components/MainPage/sections/AlertSections/LowFunds/LowFunds.tsx +++ b/frontend/components/MainPage/sections/AlertSections/LowFunds/LowFunds.tsx @@ -1,6 +1,8 @@ import { round } from 'lodash'; import { useMemo } from 'react'; +import { getNativeTokenSymbol } from '@/config/tokens'; +import { TokenSymbol } from '@/enums/Token'; import { WalletType } from '@/enums/Wallet'; import { useMasterBalances } from '@/hooks/useBalanceContext'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; @@ -22,8 +24,9 @@ export const LowFunds = () => { masterSafeNativeGasBalance, } = useMasterBalances(); - const { nativeBalancesByChain, olasBalancesByChain, isInitialFunded } = - useNeedsFunds(selectedStakingProgramId); + const { balancesByChain, isInitialFunded } = useNeedsFunds( + selectedStakingProgramId, + ); const { tokenSymbol, masterThresholds } = useLowFundsDetails(); const chainId = selectedAgentConfig.evmHomeChainId; @@ -50,15 +53,14 @@ export const LowFunds = () => { // Show the empty funds alert if the agent is not funded const isEmptyFundsVisible = useMemo(() => { if (!isBalanceLoaded) return false; - if (!olasBalancesByChain) return false; - if (!nativeBalancesByChain) return false; + if (!balancesByChain) return false; // If the agent is not funded, will be displayed if (!isInitialFunded) return false; if ( - round(nativeBalancesByChain[chainId], 2) === 0 && - round(olasBalancesByChain[chainId], 2) === 0 && + round(balancesByChain[chainId][getNativeTokenSymbol(chainId)], 2) === 0 && + round(balancesByChain[chainId][TokenSymbol.OLAS], 2) === 0 && isSafeSignerBalanceLow ) { return true; @@ -69,8 +71,7 @@ export const LowFunds = () => { isBalanceLoaded, isInitialFunded, chainId, - nativeBalancesByChain, - olasBalancesByChain, + balancesByChain, isSafeSignerBalanceLow, ]); diff --git a/frontend/components/MainPage/sections/AlertSections/LowFunds/MainNeedsFunds.tsx b/frontend/components/MainPage/sections/AlertSections/LowFunds/MainNeedsFunds.tsx index 60a7169e7..8b4d744c7 100644 --- a/frontend/components/MainPage/sections/AlertSections/LowFunds/MainNeedsFunds.tsx +++ b/frontend/components/MainPage/sections/AlertSections/LowFunds/MainNeedsFunds.tsx @@ -18,6 +18,7 @@ export const MainNeedsFunds = () => { const { hasEnoughEthForInitialFunding, hasEnoughOlasForInitialFunding, + hasEnoughAdditionalTokensForInitialFunding, isInitialFunded, needsInitialFunding, } = useNeedsFunds(selectedStakingProgramId); @@ -54,7 +55,10 @@ export const MainNeedsFunds = () => { } diff --git a/frontend/components/MainPage/sections/AlertSections/NewStakingProgramAlert.tsx b/frontend/components/MainPage/sections/AlertSections/NewStakingProgramAlert.tsx index cecb41056..4fe4a4309 100644 --- a/frontend/components/MainPage/sections/AlertSections/NewStakingProgramAlert.tsx +++ b/frontend/components/MainPage/sections/AlertSections/NewStakingProgramAlert.tsx @@ -1,25 +1,25 @@ import { Button, Flex, Typography } from 'antd'; import { Pages } from '@/enums/Pages'; -import { StakingProgramId } from '@/enums/StakingProgram'; import { usePageState } from '@/hooks/usePageState'; -import { useStakingProgram } from '@/hooks/useStakingProgram'; import { CustomAlert } from '../../../Alert'; const { Text } = Typography; +// TODO: need to figure out how to understand if there are new staking contracts +// To show this alert; also need to hide it, when a use clicks "review" export const NewStakingProgramAlert = () => { const { goto } = usePageState(); - const { activeStakingProgramId, isActiveStakingProgramLoaded } = - useStakingProgram(); + // const { activeStakingProgramId, isActiveStakingProgramLoaded } = + // useStakingProgram(); - // TODO: remove single staking program check - if ( - !isActiveStakingProgramLoaded || - activeStakingProgramId !== StakingProgramId.OptimusAlpha - ) - return null; + // // TODO: remove single staking program check + // if ( + // !isActiveStakingProgramLoaded || + // activeStakingProgramId !== StakingProgramId.OptimusAlpha + // ) + // return null; return ( { {isBackupViaSafeEnabled && } - + {/* */} diff --git a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx index a9b73b55b..90007709c 100644 --- a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx +++ b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx @@ -18,7 +18,6 @@ import { useSetup } from '@/hooks/useSetup'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { copyToClipboard } from '@/utils/copyToClipboard'; import { delayInSeconds } from '@/utils/delay'; -import { formatEther } from '@/utils/numberFormatters'; import { SetupCreateHeader } from './SetupCreateHeader'; @@ -192,9 +191,7 @@ export const SetupEoaFunding = () => { return ( diff --git a/frontend/config/agents.ts b/frontend/config/agents.ts index dca343224..c0f5b7f02 100644 --- a/frontend/config/agents.ts +++ b/frontend/config/agents.ts @@ -97,23 +97,28 @@ export const AGENT_CONFIG: { middlewareHomeChainId: MiddlewareChain.MODE, requiresAgentSafesOn: [EvmChainId.Mode], agentSafeFundingRequirements: { - [EvmChainId.Mode]: 5260000000000000, // 0.00526 eth + [EvmChainId.Mode]: 0.0005, + }, + additionalRequirements: { + [EvmChainId.Mode]: { + [TokenSymbol.USDC]: 16, + }, }, operatingThresholds: { [WalletOwnerType.Master]: { [WalletType.EOA]: { - [TokenSymbol.ETH]: 0.0001, // TODO: ensure this is correct + [TokenSymbol.ETH]: 0.0002, }, [WalletType.Safe]: { - [TokenSymbol.ETH]: 0.0001, // TODO: ensure this is correct + [TokenSymbol.ETH]: 0.001, }, }, [WalletOwnerType.Agent]: { [WalletType.EOA]: { - [TokenSymbol.ETH]: 0.0001, // TODO: ensure this is correct + [TokenSymbol.ETH]: 0.00005, }, [WalletType.Safe]: { - [TokenSymbol.ETH]: 0.0001, // TODO: ensure this is correct + [TokenSymbol.ETH]: 0.0005, }, }, }, diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index f09d32691..08fcf0719 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -110,6 +110,17 @@ export const MODE_TOKEN_CONFIG: ChainTokenConfig = { tokenType: TokenType.Erc20, symbol: TokenSymbol.OLAS, }, + /** + * @warning USDC is a special case, it has 6 decimals, not 18. + * https://explorer.mode.network/address/0xd988097fb8612cc24eeC14542bC03424c656005f?tab=read_contract#313ce567 + * @note When parsing or formatting units, use `decimals` (6) instead of the standard `ether` sizing (10^18). + */ + [TokenSymbol.USDC]: { + address: '0xd988097fb8612cc24eeC14542bC03424c656005f', + decimals: 6, + tokenType: TokenType.Erc20, + symbol: TokenSymbol.USDC, + }, }; export const TOKEN_CONFIG = { diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 5ba80157a..5292d7236 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -280,10 +280,10 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ agent_id: 40, threshold: 1, use_staking: true, - cost_of_bond: 20000000000000000000, - monthly_gas_estimate: 5260000000000000, + cost_of_bond: +parseEther(20), + monthly_gas_estimate: +parseEther(0.00516), fund_requirements: { - agent: 5000000000000000, + agent: +parseEther(0.001), safe: 0, }, }, diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index c28716cd4..e377c2adc 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -28,7 +28,7 @@ import { StakedAgentService } from '@/service/agents/StakedAgentService'; import { Address } from '@/types/Address'; import { Maybe } from '@/types/Util'; import { asEvmChainId } from '@/utils/middlewareHelpers'; -import { formatEther } from '@/utils/numberFormatters'; +import { formatUnits } from '@/utils/numberFormatters'; import { MasterWalletContext } from './MasterWalletProvider'; import { OnlineStatusContext } from './OnlineStatusProvider'; @@ -228,6 +228,7 @@ const getCrossChainWalletBalances = async ( tokenType, symbol: tokenSymbol, address: tokenAddress, + decimals, } of Object.values(tokensOnChain)) { const isNative = tokenType === TokenType.NativeGas; const isErc20 = tokenType === TokenType.Erc20; @@ -258,7 +259,7 @@ const getCrossChainWalletBalances = async ( evmChainId: providerEvmChainId, symbol: tokenSymbol, isNative: true, - balance: Number(formatEther(balance)), + balance: Number(formatUnits(balance)), }), ); } @@ -287,7 +288,7 @@ const getCrossChainWalletBalances = async ( evmChainId: providerEvmChainId, symbol: tokenSymbol, isNative: false, - balance: Number(formatEther(erc20Balances[index])), + balance: Number(formatUnits(erc20Balances[index], decimals)), }), ) as WalletBalanceResult[]; diff --git a/frontend/enums/Agent.ts b/frontend/enums/Agent.ts index 77c0f95a7..62ed45380 100644 --- a/frontend/enums/Agent.ts +++ b/frontend/enums/Agent.ts @@ -2,7 +2,7 @@ export const AgentType = { PredictTrader: 'trader', // Optimus: 'optimus', Memeooorr: 'memeooorr', - Modius: 'Modius', + Modius: 'modius', } as const; export type AgentType = (typeof AgentType)[keyof typeof AgentType]; diff --git a/frontend/hooks/useNeedsFunds.ts b/frontend/hooks/useNeedsFunds.ts index 52e3deae2..508040821 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -18,10 +18,11 @@ import { useStore } from './useStore'; export const useNeedsFunds = (stakingProgramId: Maybe) => { const { storeState } = useStore(); - const { selectedAgentType } = useServices(); + const { selectedAgentType, selectedAgentConfig } = useServices(); const serviceTemplate = SERVICE_TEMPLATES.find( (template) => template.agentType === selectedAgentType, ); + const { selectedStakingProgramId } = useStakingProgram(); const { isLoaded: isBalanceLoaded } = useBalanceContext(); @@ -52,38 +53,48 @@ export const useNeedsFunds = (stakingProgramId: Maybe) => { if (!resolvedStakingProgramId) return; + // Gas requirements const gasEstimate = config.monthly_gas_estimate; const monthlyGasEstimate = Number(formatUnits(`${gasEstimate}`, 18)); + const nativeTokenSymbol = getNativeTokenSymbol(evmChainId); + + // OLAS staking requirements const minimumStakedAmountRequired = STAKING_PROGRAMS[evmChainId]?.[resolvedStakingProgramId] ?.stakingRequirements?.[TokenSymbol.OLAS] || 0; - const nativeTokenSymbol = getNativeTokenSymbol(evmChainId); + // Additional tokens requirements + const additionalRequirements = + selectedAgentConfig.additionalRequirements?.[evmChainId] ?? {}; results[evmChainId] = { [TokenSymbol.OLAS]: minimumStakedAmountRequired, [nativeTokenSymbol]: monthlyGasEstimate, - // TODO: extend with any further erc20s.. + ...additionalRequirements, }; }, ); return results; - }, [selectedStakingProgramId, serviceTemplate, stakingProgramId]); + }, [ + selectedAgentConfig.additionalRequirements, + selectedStakingProgramId, + serviceTemplate, + stakingProgramId, + ]); /** - * Native balances by chain + * Balances by chain */ - const nativeBalancesByChain = useMemo(() => { + const balancesByChain = useMemo(() => { if (isNil(masterSafeBalances)) return; return masterSafeBalances.reduce<{ - [chainId: number]: number; + [chainId: number]: { [symbol: string]: number }; }>((acc, { symbol, balance, evmChainId }) => { - if (getNativeTokenSymbol(evmChainId) !== symbol) return acc; - - if (!acc[evmChainId]) acc[evmChainId] = 0; - acc[evmChainId] += balance; + if (!acc[evmChainId]) acc[evmChainId] = { [symbol]: 0 }; + if (!acc[evmChainId][symbol]) acc[evmChainId][symbol] = 0; + acc[evmChainId][symbol] += balance; return acc; }, {}); @@ -95,53 +106,69 @@ export const useNeedsFunds = (stakingProgramId: Maybe) => { const hasEnoughEthForInitialFunding = useMemo(() => { if (isNil(serviceFundRequirements)) return; if (isNil(masterSafeBalances)) return; - if (!nativeBalancesByChain) return; + if (!balancesByChain) return; const chainIds = Object.keys(serviceFundRequirements).map(Number); return chainIds.every((chainId) => { const nativeTokenSymbol = getNativeTokenSymbol(chainId); - const nativeTokenBalance = nativeBalancesByChain[chainId] || 0; + const nativeTokenBalance = + balancesByChain[chainId][nativeTokenSymbol] || 0; const nativeTokenRequired = serviceFundRequirements[chainId]?.[nativeTokenSymbol] || 0; return nativeTokenBalance >= nativeTokenRequired; }); - }, [serviceFundRequirements, nativeBalancesByChain, masterSafeBalances]); + }, [serviceFundRequirements, balancesByChain, masterSafeBalances]); /** - * OLAS balances by chain + * Check if the agent has enough OLAS for initial funding */ - const olasBalancesByChain = useMemo(() => { - if (!masterSafeBalances) return; - - return masterSafeBalances.reduce<{ - [chainId: number]: number; - }>((acc, { symbol, balance, evmChainId }) => { - if (TokenSymbol.OLAS !== symbol) return acc; - - if (!acc[evmChainId]) acc[evmChainId] = 0; - acc[evmChainId] += balance; - - return acc; - }, {}); - }, [masterSafeBalances]); - const hasEnoughOlasForInitialFunding = useMemo(() => { if (!serviceFundRequirements) return; if (!masterSafeBalances) return; - if (!olasBalancesByChain) return; + if (!balancesByChain) return; const chainIds = Object.keys(serviceFundRequirements).map(Number); return chainIds.every((chainId) => { - const olasBalance = olasBalancesByChain[chainId] || 0; + const olasBalance = balancesByChain[chainId][TokenSymbol.OLAS] || 0; const olasRequired = serviceFundRequirements[chainId]?.[TokenSymbol.OLAS] || 0; return olasBalance >= olasRequired; }); - }, [masterSafeBalances, olasBalancesByChain, serviceFundRequirements]); + }, [masterSafeBalances, balancesByChain, serviceFundRequirements]); + + /** + * Check if the agent requires additional tokens and has enough for initial funding + */ + const hasEnoughAdditionalTokensForInitialFunding = useMemo(() => { + if (isNil(serviceFundRequirements)) return; + if (isNil(masterSafeBalances)) return; + if (!balancesByChain) return; + + const chainIds = Object.keys(serviceFundRequirements).map(Number); + + return chainIds.every((chainId) => { + const nativeTokenSymbol = getNativeTokenSymbol(chainId); + const additionalTokens = Object.keys( + serviceFundRequirements[chainId], + ).filter( + (token) => token !== TokenSymbol.OLAS && token !== nativeTokenSymbol, + ); + + if (additionalTokens.length === 0) return true; + + return additionalTokens.every((tokenSymbol) => { + const tokenBalance = balancesByChain[chainId][tokenSymbol] || 0; + const tokenRequired = + serviceFundRequirements[chainId]?.[tokenSymbol] || 0; + + return tokenBalance >= tokenRequired; + }); + }); + }, [serviceFundRequirements, masterSafeBalances, balancesByChain]); /** * Check if the agent needs initial funding (both eth and olas) @@ -149,10 +176,15 @@ export const useNeedsFunds = (stakingProgramId: Maybe) => { const needsInitialFunding: boolean = useMemo(() => { if (isInitialFunded) return false; if (!isBalanceLoaded) return false; - if (hasEnoughEthForInitialFunding && hasEnoughOlasForInitialFunding) + if ( + hasEnoughEthForInitialFunding && + hasEnoughOlasForInitialFunding && + hasEnoughAdditionalTokensForInitialFunding + ) return false; return true; }, [ + hasEnoughAdditionalTokensForInitialFunding, hasEnoughEthForInitialFunding, hasEnoughOlasForInitialFunding, isBalanceLoaded, @@ -162,8 +194,8 @@ export const useNeedsFunds = (stakingProgramId: Maybe) => { return { hasEnoughEthForInitialFunding, hasEnoughOlasForInitialFunding, - nativeBalancesByChain, - olasBalancesByChain, + hasEnoughAdditionalTokensForInitialFunding, + balancesByChain, serviceFundRequirements, isInitialFunded, needsInitialFunding, diff --git a/frontend/types/Agent.ts b/frontend/types/Agent.ts index 2ccafb198..624ce2018 100644 --- a/frontend/types/Agent.ts +++ b/frontend/types/Agent.ts @@ -12,6 +12,9 @@ export type AgentConfig = { requiresAgentSafesOn: EvmChainId[]; agentSafeFundingRequirements: Record; requiresMasterSafesOn: EvmChainId[]; + additionalRequirements?: Partial< + Record>> + >; serviceApi: typeof PredictTraderService; displayName: string; description: string; diff --git a/frontend/types/ElectronApi.ts b/frontend/types/ElectronApi.ts index a15c18c37..712ecfedb 100644 --- a/frontend/types/ElectronApi.ts +++ b/frontend/types/ElectronApi.ts @@ -4,6 +4,7 @@ export type ElectronStore = { environmentName?: string; isInitialFunded_trader?: boolean; isInitialFunded_memeooorr?: boolean; + isInitialFunded_modius?: boolean; firstStakingRewardAchieved?: boolean; firstRewardNotificationShown?: boolean; agentEvictionAlertShown?: boolean; From 2e69f412e354014ee066832ae13d013b7235e31d Mon Sep 17 00:00:00 2001 From: Atatakai Date: Thu, 19 Dec 2024 21:23:07 +0400 Subject: [PATCH 2/2] Update frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx Co-authored-by: Mohan --- .../sections/AlertSections/LowFunds/FundsToActivate.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx b/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx index 85534c651..81bf692f6 100644 --- a/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx +++ b/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx @@ -60,7 +60,7 @@ export const FundsToActivate = ({ (token) => token !== TokenSymbol.OLAS && token !== nativeTokenSymbol, ); - if (additionalTokens.length === 0) []; + if (additionalTokens.length === 0) return []; return additionalTokens.map((tokenSymbol) => { const token = serviceFundRequirements[homeChainId][tokenSymbol];