diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index f576c63b2..6d73eb1a8 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -1,4 +1,4 @@ -import { Button, ButtonProps } from 'antd'; +import { Button, ButtonProps, message } from 'antd'; import { isNil, sum } from 'lodash'; import { useCallback, useMemo } from 'react'; @@ -7,17 +7,26 @@ import { CHAIN_CONFIG } from '@/config/chains'; import { MechType } from '@/config/mechs'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; +import { Pages } from '@/enums/Pages'; +import { SettingsScreen } from '@/enums/SettingsScreen'; import { TokenSymbol } from '@/enums/Token'; -import { WalletOwnerType, WalletType } from '@/enums/Wallet'; +import { + MasterEoa, + MasterSafe, + WalletOwnerType, + WalletType, +} from '@/enums/Wallet'; import { useBalanceContext, useMasterBalances, useServiceBalances, } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; -import { useMultisigs } from '@/hooks/useMultisig'; +import { MultisigOwners, useMultisigs } from '@/hooks/useMultisig'; +import { usePageState } from '@/hooks/usePageState'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; +import { useSettings } from '@/hooks/useSettings'; import { useActiveStakingContractDetails, useStakingContractContext, @@ -27,6 +36,7 @@ import { useStore } from '@/hooks/useStore'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { ServicesService } from '@/service/Services'; import { WalletService } from '@/service/Wallet'; +import { AgentConfig } from '@/types/Agent'; import { delayInSeconds } from '@/utils/delay'; /** Button used to start / deploy the agent */ @@ -34,6 +44,9 @@ export const AgentNotRunningButton = () => { const { storeState } = useStore(); const { showNotification } = useElectronApi(); + const { goto: gotoPage } = usePageState(); + const { goto: gotoSettings } = useSettings(); + const { masterWallets, masterSafes, masterEoa } = useMasterWalletContext(); const { selectedService, @@ -186,51 +199,6 @@ export const AgentNotRunningButton = () => { setIsBalancePollingPaused, setIsStakingContractInfoPollingPaused, ]); - - const createSafeIfNeeded = useCallback(async () => { - const selectedChainHasMasterSafe = masterSafes?.some( - (masterSafe) => - masterSafe.evmChainId === selectedAgentConfig.evmHomeChainId, - ); - - if (selectedChainHasMasterSafe) return; - - // 1. check for other safe owners on other chains - const otherChainOwners = new Set( - masterSafesOwners - ?.filter( - (masterSafe) => - masterSafe.evmChainId !== selectedAgentConfig.evmHomeChainId, - ) - .map((masterSafe) => masterSafe.owners) - .flat(), - ); - - // 2. remove master eoa from the list - if (masterEoa) otherChainOwners.delete(masterEoa?.address); - - // 3. if there's more than one signer, there's a disrepancy, alert user - if (otherChainOwners.size > 1) { - showNotification?.( - 'You have safes on other chains. Please make sure you use the same signer on all chains.', - ); - return; - } - - // 4. otherwise, create a new safe with the same signer - await WalletService.createSafe( - selectedAgentConfig.middlewareHomeChainId, - [...otherChainOwners][0], - ); - }, [ - masterEoa, - masterSafes, - masterSafesOwners, - selectedAgentConfig.evmHomeChainId, - selectedAgentConfig.middlewareHomeChainId, - showNotification, - ]); - /** * @note only create a service if `service` does not exist */ @@ -319,7 +287,19 @@ export const AgentNotRunningButton = () => { overrideSelectedServiceStatus(MiddlewareDeploymentStatus.DEPLOYING); try { - await createSafeIfNeeded(); + await createSafeIfNeeded({ + masterSafes, + masterSafesOwners, + masterEoa, + selectedAgentConfig, + gotoBackupPage: () => { + gotoPage(Pages.Settings); + gotoSettings(SettingsScreen.AddBackupWallet); + }, + gotoBackupSafePage: () => { + gotoPage(Pages.AddBackupWalletViaSafe); + }, + }); await deployAndStartService(); } catch (error) { console.error('Error while starting the agent:', error); @@ -344,10 +324,15 @@ export const AgentNotRunningButton = () => { }, [ masterWallets, pauseAllPolling, - resumeAllPolling, overrideSelectedServiceStatus, - createSafeIfNeeded, + resumeAllPolling, + masterSafes, + masterSafesOwners, + masterEoa, + selectedAgentConfig, deployAndStartService, + gotoPage, + gotoSettings, showNotification, updateStatesSequentially, ]); @@ -363,3 +348,64 @@ export const AgentNotRunningButton = () => { return ; }; + +export const createSafeIfNeeded = async ({ + masterSafes, + masterSafesOwners, + masterEoa, + selectedAgentConfig, + gotoBackupPage, + gotoBackupSafePage, +}: { + selectedAgentConfig: AgentConfig; + gotoBackupPage: () => void; + gotoBackupSafePage: () => void; + masterEoa?: MasterEoa; + masterSafes?: MasterSafe[]; + masterSafesOwners?: MultisigOwners[]; +}) => { + const selectedChainHasMasterSafe = masterSafes?.some( + (masterSafe) => + masterSafe.evmChainId === selectedAgentConfig.evmHomeChainId, + ); + + if (selectedChainHasMasterSafe) return; + + // 1. get safe owners on other chains + const otherChainOwners = new Set( + masterSafesOwners + ?.filter( + (masterSafe) => + masterSafe.evmChainId !== selectedAgentConfig.evmHomeChainId, + ) + .map((masterSafe) => masterSafe.owners) + .flat(), + ); + + // 2. remove master eoa from the set, to find backup signers + if (masterEoa) otherChainOwners.delete(masterEoa?.address); + + // 3. if there are no signers, the user needs to add a backup signer + + if (otherChainOwners.size <= 0) { + message.error( + 'A backup signer is required to create a new safe on the home chain. Please add a backup signer.', + ); + gotoBackupPage(); + throw new Error('No backup signers found'); + } + + if (otherChainOwners.size !== 1) { + message.error( + 'The same backup signer address must be used on all chains. Please remove any extra backup signers.', + ); + gotoBackupSafePage(); + throw new Error('Multiple backup signers found'); + } + + // 4. otherwise, create a new safe with the same signer + await WalletService.createSafe( + selectedAgentConfig.middlewareHomeChainId, + [...otherChainOwners][0], + ); +};