From 411040bf4648a0c46e8a1a87c7f71ed41093bb2c Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:45:48 +0000 Subject: [PATCH 01/45] remove Array<> --- frontend/client/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 93ebb1db9..1e00ca252 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -89,11 +89,11 @@ export type UpdateServicePayload = { }; export type DeleteServicesPayload = { - hashes: Array; + hashes: ServiceHash[]; }; export type DeleteServicesResponse = { - hashes: Array; + hashes: ServiceHash[]; }; export type AppInfo = { From 103ac48a52df0085567da2d138b8a211ff0ecf62 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:46:07 +0000 Subject: [PATCH 02/45] update hook usage --- frontend/components/Marketplace/Marketplace.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/Marketplace/Marketplace.tsx b/frontend/components/Marketplace/Marketplace.tsx index 1d2ea6c75..2c7afc6b9 100644 --- a/frontend/components/Marketplace/Marketplace.tsx +++ b/frontend/components/Marketplace/Marketplace.tsx @@ -1,10 +1,10 @@ import { Flex } from 'antd'; import { MarketplaceItemCard } from './MarketplaceItemCard'; import { useMemo } from 'react'; -import { useMarketplace } from '@/hooks'; +import { useServiceTemplates } from '@/hooks'; export const Marketplace = () => { - const { getServiceTemplates } = useMarketplace(); + const { getServiceTemplates } = useServiceTemplates(); const serviceTemplates = useMemo( () => getServiceTemplates(), From ac5f00db63d45a61babe6937ba63659f5d55ecc9 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:46:28 +0000 Subject: [PATCH 03/45] reset spawn on error page button click --- frontend/components/Spawn/SpawnError.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/components/Spawn/SpawnError.tsx b/frontend/components/Spawn/SpawnError.tsx index 3d5e2085d..97ec1390e 100644 --- a/frontend/components/Spawn/SpawnError.tsx +++ b/frontend/components/Spawn/SpawnError.tsx @@ -1,3 +1,4 @@ +import { useSpawn } from '@/hooks'; import { Button, Flex, Typography } from 'antd'; import { useRouter } from 'next/router'; @@ -6,11 +7,15 @@ type SpawnErrorProps = { }; export const SpawnError = ({ message }: SpawnErrorProps) => { + const { resetSpawn } = useSpawn(); const router = useRouter(); return ( {message} - From 817d8efb15159ac44f5ba8c42d4956b270cbe0fc Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:46:40 +0000 Subject: [PATCH 04/45] Refactor SpawnMasterWalletFunding component --- .../Spawn/SpawnMasterWalletFunding.tsx | 66 ++++++++----------- 1 file changed, 28 insertions(+), 38 deletions(-) diff --git a/frontend/components/Spawn/SpawnMasterWalletFunding.tsx b/frontend/components/Spawn/SpawnMasterWalletFunding.tsx index 6b64c400e..9c36bfe93 100644 --- a/frontend/components/Spawn/SpawnMasterWalletFunding.tsx +++ b/frontend/components/Spawn/SpawnMasterWalletFunding.tsx @@ -2,8 +2,7 @@ import { SpawnScreen } from '@/enums'; import { Funding } from './Funding/Funding'; import { FundRequirementETH } from './Funding/FundRequirement/FundRequirementETH'; import { useAppInfo, useSpawn } from '@/hooks'; -import { useEffect, useMemo, useState } from 'react'; -import { AddressNumberRecord } from '@/types'; +import { useEffect, useState } from 'react'; import { Spin } from 'antd'; import EthersService from '@/service/Ethers'; @@ -12,51 +11,42 @@ export const SpawnMasterWalletFunding = ({ }: { nextPage: SpawnScreen; }) => { - const { setSpawnData, rpc } = useSpawn(); + const { setSpawnData, rpc, masterWalletFundRequirements } = useSpawn(); const { userPublicKey } = useAppInfo(); - - const [masterWalletBalance, setMasterWalletBalance] = useState< - number | undefined - >(); - - const masterWalletFundRequirements: AddressNumberRecord | undefined = useMemo( - () => - userPublicKey - ? { - [userPublicKey]: 1, - } - : undefined, - [userPublicKey], - ); - - const isMasterWalletFunded: boolean | undefined = useMemo( - () => - userPublicKey && - masterWalletBalance !== undefined && - masterWalletFundRequirements - ? masterWalletBalance >= masterWalletFundRequirements[userPublicKey] - : undefined, - [masterWalletBalance, masterWalletFundRequirements, userPublicKey], - ); + const [isInitialLoaded, setIsInitialLoaded] = useState(false); useEffect(() => { - userPublicKey && - EthersService.getEthBalance(userPublicKey, rpc).then( - setMasterWalletBalance, - ); - }, [rpc, userPublicKey]); + if (!isInitialLoaded && userPublicKey) { + EthersService.getEthBalance(userPublicKey, rpc).then((balance) => { + setSpawnData((prev) => ({ + ...prev, + masterWalletFundRequirements: { + ...prev, + [userPublicKey]: { + ...masterWalletFundRequirements[userPublicKey], + received: + balance >= masterWalletFundRequirements[userPublicKey].required, + }, + }, + })); + setIsInitialLoaded(true); + }); + } + }, [ + isInitialLoaded, + masterWalletFundRequirements, + rpc, + setSpawnData, + userPublicKey, + ]); // if not inital loaded, show loader - if ( - masterWalletBalance === undefined || - isMasterWalletFunded === undefined || - masterWalletFundRequirements === undefined - ) { + if (masterWalletFundRequirements === undefined || !isInitialLoaded) { return ; } // if master wallet is already funded, don't show the funding component, skip to next page - if (isMasterWalletFunded) { + if (userPublicKey && masterWalletFundRequirements[userPublicKey].received) { setSpawnData((prev) => ({ ...prev, screen: nextPage })); return <>; } From 06078765ee7d605f19d006691c2900c37b5b85aa Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:00 +0000 Subject: [PATCH 05/45] Fix debounceCheckRpc bug in SpawnRPC component --- frontend/components/Spawn/SpawnRPC.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/components/Spawn/SpawnRPC.tsx b/frontend/components/Spawn/SpawnRPC.tsx index c8e8abe73..2ab520f24 100644 --- a/frontend/components/Spawn/SpawnRPC.tsx +++ b/frontend/components/Spawn/SpawnRPC.tsx @@ -41,11 +41,10 @@ export const SpawnRPC = ({ nextPage }: { nextPage: SpawnScreen }) => { [setSpawnData], ); - // eslint-disable-next-line react-hooks/exhaustive-deps const debounceCheckRpc = useCallback( debounce((rpcInput: string) => { if (isCheckingRpc) return; - if (!rpcInput || rpc.slice(0, 4) !== 'http') { + if (!rpcInput || rpcInput.slice(0, 4) !== 'http') { setRpcState(RPCState.INVALID); return; } @@ -60,6 +59,8 @@ export const SpawnRPC = ({ nextPage }: { nextPage: SpawnScreen }) => { }) .finally(() => setIsCheckingRpc(false)); }, 1000), + // Does not require deps; updating the function will destroy the debounce + // eslint-disable-next-line react-hooks/exhaustive-deps [], ); From b401f7a3301c3d5af03d3c9520df42a8f3ea0619 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:10 +0000 Subject: [PATCH 06/45] Refactor SpawnStakingCheck component and create service based on staking option --- .../components/Spawn/SpawnStakingCheck.tsx | 111 ++++++------------ 1 file changed, 38 insertions(+), 73 deletions(-) diff --git a/frontend/components/Spawn/SpawnStakingCheck.tsx b/frontend/components/Spawn/SpawnStakingCheck.tsx index 4e15d3f44..883d510e6 100644 --- a/frontend/components/Spawn/SpawnStakingCheck.tsx +++ b/frontend/components/Spawn/SpawnStakingCheck.tsx @@ -1,9 +1,8 @@ import { Service } from '@/client'; import { TOKENS } from '@/constants'; import { SpawnScreen } from '@/enums'; -import { useServices, useAppInfo, useSpawn } from '@/hooks'; +import { useAppInfo, useSpawn } from '@/hooks'; import EthersService from '@/service/Ethers'; -import { Address, AddressNumberRecord } from '@/types'; import { Button, Flex, Skeleton, Typography, message } from 'antd'; import { ethers } from 'ethers'; import { useCallback, useMemo, useState } from 'react'; @@ -18,8 +17,13 @@ type SpawnStakingCheckProps = { }; export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { - const { setSpawnData, serviceTemplate, rpc } = useSpawn(); - const { createService } = useServices(); + const { + rpc, + serviceTemplate, + setSpawnData, + createAgentFundRequirements, + createService, + } = useSpawn(); const { userPublicKey } = useAppInfo(); const [isCreating, setIsCreating] = useState(false); @@ -29,65 +33,31 @@ export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { * Creates service, then performs relevant state updates */ const create = useCallback( - async (useStaking: boolean) => { + async ({ isStaking }: { isStaking: boolean }) => { if (isCreating) { message.error('Service creation already in progress'); return; } - if (!serviceTemplate || !rpc) { - setSpawnData((prev) => ({ ...prev, screen: SpawnScreen.ERROR })); - return; - } - setIsCreating(true); - let service: Service; try { - service = await createService({ - ...serviceTemplate, - configuration: { - ...serviceTemplate.configuration, - rpc, - use_staking: useStaking, - }, - }); + const service: Service | undefined = await createService(isStaking); + if (!service) throw new Error('Failed to create service'); + createAgentFundRequirements(); } catch (e) { message.error('Failed to create service'); + } finally { setIsCreating(false); - return; - } - - // Set agent funding requirements - let agentFundRequirements: AddressNumberRecord = {}; - if (service.chain_data?.instances) { - agentFundRequirements = service.chain_data.instances.reduce( - (acc: AddressNumberRecord, address: Address) => ({ - ...acc, - [address]: serviceTemplate.configuration.fund_requirements.agent, - }), - {}, - ); - } - - // Set multisig funding requirements from multisig/safe - if (service.chain_data?.multisig) { - const { multisig } = service.chain_data; - const { safe } = serviceTemplate.configuration.fund_requirements; - agentFundRequirements[multisig] = safe; } - - setSpawnData((prev) => ({ ...prev, agentFundRequirements })); - - return service; }, - [createService, isCreating, rpc, serviceTemplate, setSpawnData], + [createService, isCreating, createAgentFundRequirements], ); /** * Checks if the user has the required OLAS to stake */ - const preflightStakingCheck = useCallback((): Promise => { + const preflightStakingCheck = useCallback(async (): Promise => { if (!userPublicKey) { return Promise.reject('No public key found'); } @@ -119,6 +89,8 @@ export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { const handleYes = async () => { setButtonClicked(ButtonOptions.YES); + const isStaking = true; + const canStake: boolean = await preflightStakingCheck().catch((e) => { message.error(e); return false; @@ -129,40 +101,33 @@ export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { return setButtonClicked(undefined); } - const service: Service | undefined = await create(true); - - if (!service) { - message.error('Failed to create service'); - } else { - message.success('Service created successfully'); - - setSpawnData((prev) => ({ - ...prev, - isStaking: true, - screen: nextPage, - })); - } - - setButtonClicked(undefined); + create({ isStaking }) + .then(() => { + message.success('Service created successfully'); + setSpawnData((prev) => ({ + ...prev, + isStaking, + screen: nextPage, + })); + }) + .catch(() => setButtonClicked(undefined)); }; const handleNo = async () => { setButtonClicked(ButtonOptions.NO); - const service: Service | undefined = await create(false); - - if (!service) { - message.error('Failed to create service'); - } else { - message.success('Service created successfully'); + const isStaking = false; - setSpawnData((prev) => ({ - ...prev, - isStaking: false, - screen: nextPage, - })); - } - setButtonClicked(undefined); + create({ isStaking }) + .then(() => { + message.success('Service created successfully'); + setSpawnData((prev) => ({ + ...prev, + isStaking, + screen: nextPage, + })); + }) + .catch(() => setButtonClicked(undefined)); }; const stakingRequirement: string | undefined = useMemo(() => { From 8bf188904454c0281b021f86f3078b7c3f6c450f Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:16 +0000 Subject: [PATCH 07/45] Refactor Funding component to use FundingRecord and SpawnData types --- frontend/components/Spawn/Funding/Funding.tsx | 35 +++++++------------ 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/frontend/components/Spawn/Funding/Funding.tsx b/frontend/components/Spawn/Funding/Funding.tsx index 07c44dd5e..ce4ee0099 100644 --- a/frontend/components/Spawn/Funding/Funding.tsx +++ b/frontend/components/Spawn/Funding/Funding.tsx @@ -1,12 +1,10 @@ import { COLOR } from '@/constants'; import { SpawnScreen } from '@/enums'; import { useSpawn } from '@/hooks'; -import { Address, AddressNumberRecord } from '@/types'; -import { AddressBooleanRecord } from '@/types'; +import { Address, FundingRecord, SpawnData } from '@/types'; import { TimelineItemProps, Flex, Typography, Timeline } from 'antd'; import { isEmpty } from 'lodash'; import { - useState, useMemo, useEffect, SetStateAction, @@ -15,7 +13,7 @@ import { } from 'react'; type FundRequirementComponentProps = { - setReceivedFunds: Dispatch>; + setSpawnData: Dispatch>; rpc: string; address: Address; requirement: number; @@ -25,7 +23,7 @@ type FundRequirementComponentProps = { }; type FundingProps = { - fundRequirements: AddressNumberRecord; + fundRequirements: FundingRecord; FundRequirementComponent: ( props: FundRequirementComponentProps, ) => ReactElement; @@ -45,51 +43,42 @@ export const Funding = ({ }: FundingProps) => { const { setSpawnData, rpc } = useSpawn(); - const [receivedFunds, setReceivedFunds] = useState({ - ...(Object.keys(fundRequirements) as Address[]).reduce( - (acc: AddressBooleanRecord, address: Address) => { - acc[address] = false; - return acc; - }, - {}, - ), - }); - const timelineItems: TimelineItemProps[] = useMemo( () => (Object.keys(fundRequirements) as Address[]).map((address) => { + const { required, received } = fundRequirements[address]; return { children: ( ), - color: receivedFunds[address] ? COLOR.GREEN_2 : COLOR.RED, + color: received ? COLOR.GREEN_2 : COLOR.RED, }; }) as TimelineItemProps[], [ FundRequirementComponent, contractAddress, fundRequirements, - receivedFunds, rpc, + setSpawnData, symbol, ], ); const hasSentAllFunds = useMemo(() => { if (isEmpty(fundRequirements)) return false; - return (Object.keys(receivedFunds) as Address[]).reduce( - (acc: boolean, address) => acc && receivedFunds[address], + return (Object.keys(fundRequirements) as Address[]).reduce( + (acc: boolean, address) => acc && fundRequirements[address].received, true, ); - }, [fundRequirements, receivedFunds]); + }, [fundRequirements]); useEffect(() => { hasSentAllFunds && setSpawnData((prev) => ({ ...prev, screen: nextPage })); From 76a04f3560d07c6b66436aea1d939c11641d4042 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:22 +0000 Subject: [PATCH 08/45] Refactor setReceivedFunds to setSpawnData in FundRequirement component --- .../Funding/FundRequirement/FundRequirement.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/frontend/components/Spawn/Funding/FundRequirement/FundRequirement.tsx b/frontend/components/Spawn/Funding/FundRequirement/FundRequirement.tsx index 6d03a76eb..078ec0853 100644 --- a/frontend/components/Spawn/Funding/FundRequirement/FundRequirement.tsx +++ b/frontend/components/Spawn/Funding/FundRequirement/FundRequirement.tsx @@ -1,6 +1,6 @@ import { copyToClipboard } from '@/common-util/copyToClipboard'; import { useModals } from '@/hooks'; -import { Address, AddressBooleanRecord } from '@/types'; +import { Address, SpawnData } from '@/types'; import { Button, Flex, Typography, message } from 'antd'; import { Dispatch, @@ -24,7 +24,7 @@ type FundRequirementProps = { rpc: string, contractAddress?: Address, ) => Promise; - setReceivedFunds: Dispatch>; + setSpawnData: Dispatch>; }; /** @@ -41,7 +41,7 @@ export const FundRequirement = ({ hasReceivedFunds, isErc20, getBalance, - setReceivedFunds, + setSpawnData, }: FundRequirementProps) => { const { qrModalOpen } = useModals(); @@ -77,9 +77,15 @@ export const FundRequirement = ({ .then((balance: number) => { if (balance >= requirement) { setIsPollingBalance(false); - setReceivedFunds((prev: AddressBooleanRecord) => ({ + setSpawnData((prev: SpawnData) => ({ ...prev, - [address]: true, + agentFundRequirements: { + ...prev.agentFundRequirements, + [address]: { + ...prev.agentFundRequirements[address], + received: true, + }, + }, })); message.success(`Funded ${address}`); } From b089d6c2ff497fac1b309b573a098daeb01afb4c Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:29 +0000 Subject: [PATCH 09/45] Update FundRequirementERC20.tsx imports and props --- .../Spawn/Funding/FundRequirement/FundRequirementERC20.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/Spawn/Funding/FundRequirement/FundRequirementERC20.tsx b/frontend/components/Spawn/Funding/FundRequirement/FundRequirementERC20.tsx index b110649b1..a8f309b5d 100644 --- a/frontend/components/Spawn/Funding/FundRequirement/FundRequirementERC20.tsx +++ b/frontend/components/Spawn/Funding/FundRequirement/FundRequirementERC20.tsx @@ -1,6 +1,6 @@ import { Dispatch, SetStateAction } from 'react'; import { FundRequirement } from './FundRequirement'; -import { Address, AddressBooleanRecord } from '@/types'; +import { Address, SpawnData } from '@/types'; import EthersService from '@/service/Ethers'; type FundRequirementERC20Props = { @@ -10,7 +10,7 @@ type FundRequirementERC20Props = { symbol: string; contractAddress?: Address; hasReceivedFunds: boolean; - setReceivedFunds: Dispatch>; + setSpawnData: Dispatch>; }; export const FundRequirementERC20 = (props: FundRequirementERC20Props) => { From ef139dd9272b6ae64fd0ce22955e9d5b829f3b56 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:33 +0000 Subject: [PATCH 10/45] Update FundRequirementETH.tsx imports and props --- .../Spawn/Funding/FundRequirement/FundRequirementETH.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/Spawn/Funding/FundRequirement/FundRequirementETH.tsx b/frontend/components/Spawn/Funding/FundRequirement/FundRequirementETH.tsx index 63cdf4c4c..69b0f4c75 100644 --- a/frontend/components/Spawn/Funding/FundRequirement/FundRequirementETH.tsx +++ b/frontend/components/Spawn/Funding/FundRequirement/FundRequirementETH.tsx @@ -1,6 +1,6 @@ import { Dispatch, SetStateAction } from 'react'; import { FundRequirement } from './FundRequirement'; -import { Address, AddressBooleanRecord } from '@/types'; +import { Address, SpawnData } from '@/types'; import EthersService from '@/service/Ethers'; type FundRequirementETHProps = { @@ -9,7 +9,7 @@ type FundRequirementETHProps = { requirement: number; rpc: string; hasReceivedFunds: boolean; - setReceivedFunds: Dispatch>; + setSpawnData: Dispatch>; }; export const FundRequirementETH = (props: FundRequirementETHProps) => { From f925ec10b8e0c09b0c7e0adce93a1046d1bda392 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:38 +0000 Subject: [PATCH 11/45] Refactor ServiceCard component to use updated hooks --- .../YourAgents/ServiceCard/ServiceCard.tsx | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx b/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx index f90a0c5c4..410b9591b 100644 --- a/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx +++ b/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx @@ -19,7 +19,7 @@ import { ServiceHash, ServiceTemplate, } from '@/client'; -import { useMarketplace, useServices } from '@/hooks'; +import { useServiceTemplates, useServices } from '@/hooks'; import { ServiceCardTotalBalance } from './ServiceCardTotalBalance'; import { @@ -27,20 +27,15 @@ import { SERVICE_CARD_STATUS_POLLING_INTERVAL, } from '@/constants/intervals'; import EthersService from '@/service/Ethers'; +import { ServicesService } from '@/service'; type ServiceCardProps = { service: Service; }; export const ServiceCard = ({ service }: ServiceCardProps) => { - const { - stopService, - deployService, - deleteServices, - getServiceStatus, - deleteServiceState, - } = useServices(); - const { getServiceTemplates } = useMarketplace(); + const { deleteServiceState } = useServices(); + const { getServiceTemplates } = useServiceTemplates(); const [serviceStatus, setServiceStatus] = useState< DeploymentStatus | undefined @@ -53,12 +48,12 @@ export const ServiceCard = ({ service }: ServiceCardProps) => { const updateServiceStatus = useCallback( (serviceHash: ServiceHash): Promise => - getServiceStatus(serviceHash) + ServicesService.getServiceStatus(serviceHash) .then((r: Deployment) => setServiceStatus(r.status)) .catch(() => { setServiceStatus(undefined); }), - [getServiceStatus], + [], ); useInterval( @@ -69,7 +64,7 @@ export const ServiceCard = ({ service }: ServiceCardProps) => { const handleStart = useCallback(async () => { if (isStarting) return; setIsStarting(true); - deployService(service.hash) + ServicesService.deployService(service.hash) .then(async () => { message.success('Service started successfully'); }) @@ -81,12 +76,12 @@ export const ServiceCard = ({ service }: ServiceCardProps) => { .catch(() => message.error('Failed to update service status')) .finally(() => setIsStarting(false)); }); - }, [isStarting, deployService, service.hash, updateServiceStatus]); + }, [isStarting, service.hash, updateServiceStatus]); const handleStop = useCallback(async (): Promise => { if (isStopping) return; setIsStopping(true); - stopService(service.hash) + ServicesService.stopService(service.hash) .then(() => { message.success('Service stopped successfully'); }) @@ -98,17 +93,17 @@ export const ServiceCard = ({ service }: ServiceCardProps) => { .catch(() => message.error('Failed to update service status')) .finally(() => setIsStopping(false)); }); - }, [isStopping, service.hash, stopService, updateServiceStatus]); + }, [isStopping, service.hash, updateServiceStatus]); const handleDelete = useCallback(async () => { if (isDeleting) return; setIsDeleting(true); - deleteServices([service.hash]) + ServicesService.deleteServices({ hashes: [service.hash] }) .catch(() => message.error('Failed to delete service')) .finally(() => { deleteServiceState(service.hash); }); - }, [deleteServiceState, deleteServices, isDeleting, service.hash]); + }, [deleteServiceState, isDeleting, service.hash]); const buttons: JSX.Element = useMemo(() => { if (serviceStatus === DeploymentStatus.CREATED) From 305eceb56f11eb6a9b24de120fdb3811ceeeb344 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:42 +0000 Subject: [PATCH 12/45] Refactor SpawnProvider.tsx to use SpawnData type --- .../context/SpawnProvider/SpawnProvider.tsx | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/frontend/context/SpawnProvider/SpawnProvider.tsx b/frontend/context/SpawnProvider/SpawnProvider.tsx index 9bd2b13a3..8cf503e4d 100644 --- a/frontend/context/SpawnProvider/SpawnProvider.tsx +++ b/frontend/context/SpawnProvider/SpawnProvider.tsx @@ -1,6 +1,5 @@ -import { ServiceTemplate } from '@/client'; import { SpawnScreen } from '@/enums'; -import { AddressBooleanRecord, AddressNumberRecord } from '@/types'; +import { SpawnData } from '@/types'; import { Dispatch, PropsWithChildren, @@ -9,17 +8,6 @@ import { useState, } from 'react'; -type SpawnData = { - agentFundsReceived: AddressBooleanRecord; - agentFundRequirements: AddressNumberRecord; - isStaking?: boolean; - nativeBalance?: number; - rpc: string; - screen: SpawnScreen; - serviceTemplateHash?: string; - serviceTemplate?: ServiceTemplate; -}; - type SpawnContextType = { spawnData: SpawnData; setSpawnData: Dispatch>; @@ -28,14 +16,14 @@ type SpawnContextType = { const FIRST_SPAWN_SCREEN: SpawnScreen = SpawnScreen.RPC; export const DEFAULT_SPAWN_DATA: SpawnData = { - agentFundsReceived: {}, agentFundRequirements: {}, + masterWalletFundRequirements: {}, isStaking: undefined, nativeBalance: undefined, rpc: '', screen: FIRST_SPAWN_SCREEN, - serviceTemplateHash: undefined, serviceTemplate: undefined, + service: undefined, }; export const SpawnContext = createContext({ From 788112aa75fc2226fc5c5a43bf2b21bbf1fb3a23 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:48 +0000 Subject: [PATCH 13/45] Update useMarketplace hook to useServiceTemplates hook --- frontend/hooks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/index.ts b/frontend/hooks/index.ts index 26fdde9ef..e3c9e4668 100644 --- a/frontend/hooks/index.ts +++ b/frontend/hooks/index.ts @@ -2,5 +2,5 @@ export * from './useServices'; export * from './useSpawn'; export * from './useModals'; export * from './useTabs'; -export * from './useMarketplace'; +export * from './useServiceTemplates'; export * from './useAppInfo'; From 7e86113ca0c4e5c36b75bfe5e41556aae21727ba Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:53 +0000 Subject: [PATCH 14/45] Remove useMarketplace hook --- frontend/hooks/useMarketplace.tsx | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 frontend/hooks/useMarketplace.tsx diff --git a/frontend/hooks/useMarketplace.tsx b/frontend/hooks/useMarketplace.tsx deleted file mode 100644 index e96ffe6c6..000000000 --- a/frontend/hooks/useMarketplace.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { ServiceTemplate } from '@/client'; -import { serviceTemplates } from '@/constants'; - -export const useMarketplace = () => { - const getServiceTemplates = (): ServiceTemplate[] => serviceTemplates; - const getServiceTemplate = (hash: string): ServiceTemplate | undefined => - serviceTemplates.find((template) => template.hash === hash); - - return { - getServiceTemplate, - getServiceTemplates, - }; -}; From cb8224ebae0596b1799beca10017b1765bd14e8a Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:47:59 +0000 Subject: [PATCH 15/45] Refactor useServices hook to remove unused methods --- frontend/hooks/useServices.tsx | 29 ++--------------------------- 1 file changed, 2 insertions(+), 27 deletions(-) diff --git a/frontend/hooks/useServices.tsx b/frontend/hooks/useServices.tsx index 36d4ad27e..2dd95b106 100644 --- a/frontend/hooks/useServices.tsx +++ b/frontend/hooks/useServices.tsx @@ -1,4 +1,4 @@ -import { Service, ServiceHash, ServiceTemplate } from '@/client'; +import { Service, ServiceHash } from '@/client'; import { ServicesContext } from '@/context'; import { ServicesService } from '@/service'; import { useContext } from 'react'; @@ -7,25 +7,6 @@ export const useServices = () => { const { services, updateServicesState, hasInitialLoaded, setServices } = useContext(ServicesContext); - // SERVICES SERVICE METHODS - const createService = async (serviceTemplate: Required) => - ServicesService.createService(serviceTemplate); - - const deployService = async (serviceHash: ServiceHash) => - ServicesService.deployService(serviceHash); - - const stopService = async (serviceHash: string) => - ServicesService.stopService(serviceHash); - - const deleteServices = async (hashes: ServiceHash[]) => - ServicesService.deleteServices({ hashes }); - - const getService = async (serviceHash: ServiceHash) => - ServicesService.getService(serviceHash); - - const getServiceStatus = async (serviceHash: ServiceHash) => - ServicesService.getServiceStatus(serviceHash); - // STATE METHODS const getServiceFromState = ( serviceHash: ServiceHash, @@ -40,7 +21,7 @@ export const useServices = () => { hasInitialLoaded ? services : []; const updateServiceState = (serviceHash: ServiceHash) => - getService(serviceHash).then((service: Service) => + ServicesService.getService(serviceHash).then((service: Service) => setServices((prev) => { const index = prev.findIndex((s) => s.hash === serviceHash); // findIndex returns -1 if not found if (index === -1) return [...prev, service]; @@ -54,17 +35,11 @@ export const useServices = () => { setServices((prev) => prev.filter((s) => s.hash !== serviceHash)); return { - getService, getServiceFromState, getServicesFromState, - getServiceStatus, updateServicesState, updateServiceState, deleteServiceState, - createService, - deployService, - stopService, - deleteServices, hasInitialLoaded, }; }; From 1aa9572574e79d1ee69c5a0e614cab103552c73a Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:48:03 +0000 Subject: [PATCH 16/45] Add useServiceTemplates hook --- frontend/hooks/useServiceTemplates.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 frontend/hooks/useServiceTemplates.tsx diff --git a/frontend/hooks/useServiceTemplates.tsx b/frontend/hooks/useServiceTemplates.tsx new file mode 100644 index 000000000..004a5370a --- /dev/null +++ b/frontend/hooks/useServiceTemplates.tsx @@ -0,0 +1,13 @@ +import { ServiceTemplate } from '@/client/types'; +import { serviceTemplates } from '@/constants'; + +export const useServiceTemplates = () => { + const getServiceTemplates = (): ServiceTemplate[] => serviceTemplates; + const getServiceTemplate = (hash: string): ServiceTemplate | undefined => + serviceTemplates.find((template) => template.hash === hash); + + return { + getServiceTemplate, + getServiceTemplates, + }; +}; From 80764d01c4fa271138750d6c85db14d7901acb38 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:48:08 +0000 Subject: [PATCH 17/45] Refactor useSpawn hook to improve code structure and add new functionality --- frontend/hooks/useSpawn.tsx | 88 ++++++++++++++++++++++++++++++++----- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/frontend/hooks/useSpawn.tsx b/frontend/hooks/useSpawn.tsx index 650407ac6..01fade836 100644 --- a/frontend/hooks/useSpawn.tsx +++ b/frontend/hooks/useSpawn.tsx @@ -1,17 +1,18 @@ -import { ServiceTemplate } from '@/client'; +import { Service } from '@/client'; import { DEFAULT_SPAWN_DATA, SpawnContext } from '@/context'; import { SpawnScreen } from '@/enums'; import { useCallback, useContext, useMemo } from 'react'; -import { useMarketplace } from '.'; +import { Address, FundingRecord } from '@/types'; +import { message } from 'antd'; +import { ServicesService } from '@/service'; export const useSpawn = () => { - const { getServiceTemplate } = useMarketplace(); const { spawnData, setSpawnData } = useContext(SpawnContext); - const { serviceTemplateHash, screen } = spawnData; + // MEMOS const spawnPercentage: number = useMemo(() => { // Staking path - switch (screen) { + switch (spawnData.screen) { case SpawnScreen.RPC: return 0; case SpawnScreen.STAKING_CHECK: @@ -23,12 +24,36 @@ export const useSpawn = () => { default: return 0; } - }, [screen]); + }, [spawnData.screen]); - const serviceTemplate: ServiceTemplate | undefined = useMemo(() => { - if (!serviceTemplateHash) return; - return getServiceTemplate(serviceTemplateHash); - }, [getServiceTemplate, serviceTemplateHash]); + // METHODS + const createService = useCallback( + async (useStaking: boolean): Promise => { + if (!spawnData.serviceTemplate || !spawnData.rpc) { + setSpawnData((prev) => ({ ...prev, screen: SpawnScreen.ERROR })); + return; + } + + let service: Service; + try { + service = await ServicesService.createService({ + ...spawnData.serviceTemplate, + configuration: { + ...spawnData.serviceTemplate.configuration, + rpc: spawnData.rpc, + use_staking: useStaking, + }, + }); + } catch (e) { + message.error('Failed to create service'); + return; + } + + setSpawnData((prev) => ({ ...prev, service })); + return service; + }, + [setSpawnData, spawnData.rpc, spawnData.serviceTemplate], + ); const resetSpawn = useCallback( (): void => setSpawnData(DEFAULT_SPAWN_DATA), @@ -37,11 +62,50 @@ export const useSpawn = () => { [], ); + /** + * Creates agent funding requirements in spawnData + */ + const createAgentFundRequirements = useCallback((): + | FundingRecord + | undefined => { + if (!spawnData.serviceTemplate || !spawnData.service?.chain_data.instances) + return undefined; + + // Agent funding requirements + let agentFundRequirements: FundingRecord = {}; + + const required = + spawnData.serviceTemplate.configuration.fund_requirements.agent; + + agentFundRequirements = spawnData.service.chain_data.instances.reduce( + (acc: FundingRecord, address: Address) => ({ + ...acc, + [address]: { + required, + received: false, + }, + }), + {}, + ); + + // Multisig funding requirements + if (spawnData.service.chain_data?.multisig) { + const { multisig } = spawnData.service.chain_data; + const { safe } = + spawnData.serviceTemplate.configuration.fund_requirements; + agentFundRequirements[multisig] = { required: safe, received: false }; + } + + setSpawnData((prev) => ({ ...prev, agentFundRequirements })); + }, [setSpawnData, spawnData.service, spawnData.serviceTemplate]); + return { ...spawnData, + spawnData, spawnPercentage, - serviceTemplate, - setSpawnData, + createService, resetSpawn, + setSpawnData, + createAgentFundRequirements, }; }; From 87fea34d08a7a3b0e8d910a0e6361820c98a02c8 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:48:12 +0000 Subject: [PATCH 18/45] Refactor SpawnPage component to handle different screens and add error handling --- .../pages/spawn/[serviceTemplateHash].tsx | 49 ++++++++++++++----- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/frontend/pages/spawn/[serviceTemplateHash].tsx b/frontend/pages/spawn/[serviceTemplateHash].tsx index 06352fa1b..ea6d63ccb 100644 --- a/frontend/pages/spawn/[serviceTemplateHash].tsx +++ b/frontend/pages/spawn/[serviceTemplateHash].tsx @@ -1,6 +1,6 @@ import { SpawnRPC } from '@/components/Spawn'; import { SpawnScreen } from '@/enums'; -import { useSpawn } from '@/hooks'; +import { useServices, useSpawn, useServiceTemplates } from '@/hooks'; import { GetServerSidePropsContext } from 'next'; import dynamic from 'next/dynamic'; import { ReactElement, useEffect, useMemo } from 'react'; @@ -47,30 +47,53 @@ const SpawnMasterWalletFunding = dynamic( export const getServerSideProps = async ( context: GetServerSidePropsContext, ) => { - const { serviceTemplateHash } = context.query; - return { props: { serviceTemplateHash } }; + const { serviceTemplateHash, screen } = context.query; + return { props: { serviceTemplateHash, screen: screen ? screen : null } }; }; type SpawnPageProps = { serviceTemplateHash: string; + screen: SpawnScreen | null; }; -export const SpawnPage = ({ serviceTemplateHash }: SpawnPageProps) => { - const { screen, setSpawnData } = useSpawn(); +export const SpawnPage = (props: SpawnPageProps) => { + const { getServiceFromState } = useServices(); + const { getServiceTemplate } = useServiceTemplates(); + const { setSpawnData, spawnData } = useSpawn(); useEffect(() => { - setSpawnData((prev) => { - return { + try { + const serviceTemplate = getServiceTemplate(props.serviceTemplateHash); + if (!serviceTemplate) throw new Error('Service template not found'); + if (props.screen === null) { + // No resume required + setSpawnData((prev) => ({ ...prev, serviceTemplate })); + } else { + // Funding, resume required + const service = getServiceFromState(props.serviceTemplateHash); + if (!service) throw new Error('Service not found'); + const { + ledger: { rpc }, + } = service; + setSpawnData((prev) => ({ + ...prev, + serviceTemplate, + screen: props.screen as SpawnScreen, // cast required though it's not null; TS doesn't not support typeof or instanceof for enum + rpc, + })); + } + } catch (e) { + setSpawnData((prev) => ({ ...prev, - serviceTemplateHash, - }; - }); - // Not required to run this effect on every render, only once + screen: SpawnScreen.ERROR, + })); + } + // Runs once, no deps required as it will reset "screen" state attribute // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const spawnScreen: ReactElement = useMemo(() => { - switch (screen) { + switch (spawnData.screen) { case SpawnScreen.RPC: return ; @@ -91,7 +114,7 @@ export const SpawnPage = ({ serviceTemplateHash }: SpawnPageProps) => { default: return ; } - }, [screen]); + }, [spawnData.screen]); return ( <> From bfb27a12671c18117427056876461e14db094f5f Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:48:17 +0000 Subject: [PATCH 19/45] Add 'SpawnData' type to index.ts --- frontend/types/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/types/index.ts b/frontend/types/index.ts index 31d520470..51e41edc0 100644 --- a/frontend/types/index.ts +++ b/frontend/types/index.ts @@ -1,3 +1,4 @@ export type * from './QRModalData'; export type * from './Address'; export type * from './Records'; +export type * from './SpawnData'; From 7a50a81c129381549726baab9a3a6a5c71c252f3 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:48:22 +0000 Subject: [PATCH 20/45] Add FundingRecord type to Records.ts --- frontend/types/Records.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/types/Records.ts b/frontend/types/Records.ts index b0c82ea3f..ffeb2271e 100644 --- a/frontend/types/Records.ts +++ b/frontend/types/Records.ts @@ -2,3 +2,7 @@ import { Address } from '.'; export type AddressNumberRecord = Record; export type AddressBooleanRecord = Record; +export type FundingRecord = Record< + Address, + { required: number; received: boolean } +>; From 488f6a854e598a46e0cfbf716774853d05a63047 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 10:48:26 +0000 Subject: [PATCH 21/45] Add SpawnData type definition --- frontend/types/SpawnData.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 frontend/types/SpawnData.ts diff --git a/frontend/types/SpawnData.ts b/frontend/types/SpawnData.ts new file mode 100644 index 000000000..65fccd22c --- /dev/null +++ b/frontend/types/SpawnData.ts @@ -0,0 +1,14 @@ +import { ServiceTemplate, Service } from '@/client'; +import { SpawnScreen } from '@/enums'; +import { FundingRecord } from '.'; + +export type SpawnData = { + agentFundRequirements: FundingRecord; + masterWalletFundRequirements: FundingRecord; + isStaking?: boolean; + nativeBalance?: number; + rpc: string; + screen: SpawnScreen; + serviceTemplate?: ServiceTemplate; + service?: Service; +}; From c0070510ddb2351de0a15603758801c513dc7157 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Wed, 6 Mar 2024 12:32:21 +0000 Subject: [PATCH 22/45] add createMasterFunding --- frontend/hooks/useSpawn.tsx | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/frontend/hooks/useSpawn.tsx b/frontend/hooks/useSpawn.tsx index 01fade836..76d05f06a 100644 --- a/frontend/hooks/useSpawn.tsx +++ b/frontend/hooks/useSpawn.tsx @@ -62,6 +62,23 @@ export const useSpawn = () => { [], ); + /** + * Creates master wallet funding requirements in spawnData + */ + const createMasterWalletFundRequirements = useCallback(() => { + if (!spawnData.serviceTemplate) return; + + const required = 1; + + setSpawnData((prev) => ({ + ...prev, + masterWalletFundRequirements: { + required, + received: false, + }, + })); + }, [setSpawnData, spawnData.serviceTemplate]); + /** * Creates agent funding requirements in spawnData */ @@ -107,5 +124,6 @@ export const useSpawn = () => { resetSpawn, setSpawnData, createAgentFundRequirements, + createMasterWalletFundRequirements, }; }; From dffeef2e20c5ea8f04ee5c8a212fd35f99880a34 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:30:06 +0000 Subject: [PATCH 23/45] Refactor SpawnAgentFunding to destructure spawnData --- frontend/components/Spawn/SpawnAgentFunding.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/components/Spawn/SpawnAgentFunding.tsx b/frontend/components/Spawn/SpawnAgentFunding.tsx index e6f08e61d..4f4de6793 100644 --- a/frontend/components/Spawn/SpawnAgentFunding.tsx +++ b/frontend/components/Spawn/SpawnAgentFunding.tsx @@ -8,7 +8,9 @@ type SpawnAgentFundingProps = { }; export const SpawnAgentFunding = (props: SpawnAgentFundingProps) => { - const { agentFundRequirements: fundRequirements } = useSpawn(); + const { + spawnData: { agentFundRequirements: fundRequirements }, + } = useSpawn(); return ( Date: Thu, 7 Mar 2024 19:30:14 +0000 Subject: [PATCH 24/45] Refactor SpawnMasterWalletFunding component to destructure spawnData --- .../Spawn/SpawnMasterWalletFunding.tsx | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/frontend/components/Spawn/SpawnMasterWalletFunding.tsx b/frontend/components/Spawn/SpawnMasterWalletFunding.tsx index 9c36bfe93..8f19e43d5 100644 --- a/frontend/components/Spawn/SpawnMasterWalletFunding.tsx +++ b/frontend/components/Spawn/SpawnMasterWalletFunding.tsx @@ -11,7 +11,10 @@ export const SpawnMasterWalletFunding = ({ }: { nextPage: SpawnScreen; }) => { - const { setSpawnData, rpc, masterWalletFundRequirements } = useSpawn(); + const { + setSpawnData, + spawnData: { rpc, masterWalletFundRequirements }, + } = useSpawn(); const { userPublicKey } = useAppInfo(); const [isInitialLoaded, setIsInitialLoaded] = useState(false); @@ -21,11 +24,9 @@ export const SpawnMasterWalletFunding = ({ setSpawnData((prev) => ({ ...prev, masterWalletFundRequirements: { - ...prev, [userPublicKey]: { - ...masterWalletFundRequirements[userPublicKey], - received: - balance >= masterWalletFundRequirements[userPublicKey].required, + ...prev.masterWalletFundRequirements[userPublicKey], + received: balance > 1, }, }, })); @@ -45,12 +46,6 @@ export const SpawnMasterWalletFunding = ({ return ; } - // if master wallet is already funded, don't show the funding component, skip to next page - if (userPublicKey && masterWalletFundRequirements[userPublicKey].received) { - setSpawnData((prev) => ({ ...prev, screen: nextPage })); - return <>; - } - return ( Date: Thu, 7 Mar 2024 19:30:18 +0000 Subject: [PATCH 25/45] Refactor SpawnRPC component to destructure spawnData.rpc --- frontend/components/Spawn/SpawnRPC.tsx | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/frontend/components/Spawn/SpawnRPC.tsx b/frontend/components/Spawn/SpawnRPC.tsx index 2ab520f24..257151bfd 100644 --- a/frontend/components/Spawn/SpawnRPC.tsx +++ b/frontend/components/Spawn/SpawnRPC.tsx @@ -24,7 +24,10 @@ enum RPCState { } export const SpawnRPC = ({ nextPage }: { nextPage: SpawnScreen }) => { - const { setSpawnData, rpc } = useSpawn(); + const { + setSpawnData, + spawnData: { rpc }, + } = useSpawn(); const { userPublicKey } = useAppInfo(); const [isCheckingRpc, setIsCheckingRpc] = useState(false); @@ -87,18 +90,7 @@ export const SpawnRPC = ({ nextPage }: { nextPage: SpawnScreen }) => { return; } - // TEMPORARY BALANCE CHECK (TO BE RESOLVED WITH MASTER WALLET CONTEXT & HOOK WHEN PUBLIC RPC IS AUTHORISED) - const nativeBalance: number | undefined = await EthersService.getEthBalance( - userPublicKey, - rpc, - ).catch(() => undefined); - - if (nativeBalance === undefined) { - message.error('Failed to get master wallet balance'); - return; - } - - setSpawnData((prev) => ({ ...prev, screen: nextPage, nativeBalance })); + setSpawnData((prev) => ({ ...prev, screen: nextPage })); }, [nextPage, rpc, rpcState, setSpawnData, userPublicKey]); const isContinueDisabled: boolean = useMemo( From e2543a62838c7000eff534406e45fc26d85b0938 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:30:22 +0000 Subject: [PATCH 26/45] Refactor SpawnStakingCheck component --- frontend/components/Spawn/SpawnStakingCheck.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/components/Spawn/SpawnStakingCheck.tsx b/frontend/components/Spawn/SpawnStakingCheck.tsx index 883d510e6..a0c660018 100644 --- a/frontend/components/Spawn/SpawnStakingCheck.tsx +++ b/frontend/components/Spawn/SpawnStakingCheck.tsx @@ -18,10 +18,8 @@ type SpawnStakingCheckProps = { export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { const { - rpc, - serviceTemplate, + spawnData: { rpc, serviceTemplate }, setSpawnData, - createAgentFundRequirements, createService, } = useSpawn(); const { userPublicKey } = useAppInfo(); @@ -44,14 +42,13 @@ export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { try { const service: Service | undefined = await createService(isStaking); if (!service) throw new Error('Failed to create service'); - createAgentFundRequirements(); } catch (e) { message.error('Failed to create service'); } finally { setIsCreating(false); } }, - [createService, isCreating, createAgentFundRequirements], + [createService, isCreating], ); /** From a71f96c30c425deef7275365602c2b7a70d2f312 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:30:27 +0000 Subject: [PATCH 27/45] Refactor Funding.tsx to use destructuring assignment --- frontend/components/Spawn/Funding/Funding.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/components/Spawn/Funding/Funding.tsx b/frontend/components/Spawn/Funding/Funding.tsx index ce4ee0099..189c62e33 100644 --- a/frontend/components/Spawn/Funding/Funding.tsx +++ b/frontend/components/Spawn/Funding/Funding.tsx @@ -41,7 +41,10 @@ export const Funding = ({ symbol, contractAddress, }: FundingProps) => { - const { setSpawnData, rpc } = useSpawn(); + const { + setSpawnData, + spawnData: { rpc }, + } = useSpawn(); const timelineItems: TimelineItemProps[] = useMemo( () => @@ -80,6 +83,7 @@ export const Funding = ({ ); }, [fundRequirements]); + // if all funds have been sent, move to next page useEffect(() => { hasSentAllFunds && setSpawnData((prev) => ({ ...prev, screen: nextPage })); }, [hasSentAllFunds, nextPage, setSpawnData]); From cdd8d61ee976a8dea6b000eec25c458a4b995a7e Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:30:36 +0000 Subject: [PATCH 28/45] Update fund requirement handling in FundRequirement component --- .../FundRequirement/FundRequirement.tsx | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/frontend/components/Spawn/Funding/FundRequirement/FundRequirement.tsx b/frontend/components/Spawn/Funding/FundRequirement/FundRequirement.tsx index 078ec0853..8b68784fa 100644 --- a/frontend/components/Spawn/Funding/FundRequirement/FundRequirement.tsx +++ b/frontend/components/Spawn/Funding/FundRequirement/FundRequirement.tsx @@ -77,17 +77,36 @@ export const FundRequirement = ({ .then((balance: number) => { if (balance >= requirement) { setIsPollingBalance(false); - setSpawnData((prev: SpawnData) => ({ - ...prev, - agentFundRequirements: { - ...prev.agentFundRequirements, - [address]: { - ...prev.agentFundRequirements[address], - received: true, - }, - }, - })); - message.success(`Funded ${address}`); + setSpawnData((prev: SpawnData) => { + // update agent fund requirements + if (prev.agentFundRequirements[address]) { + return { + ...prev, + agentFundRequirements: { + ...prev.agentFundRequirements, + [address]: { + ...prev.agentFundRequirements[address], + received: true, + }, + }, + }; + } + // update master wallet fund requirements + if (prev.masterWalletFundRequirements[address]) { + return { + ...prev, + masterWalletFundRequirements: { + ...prev.masterWalletFundRequirements, + [address]: { + ...prev.masterWalletFundRequirements[address], + received: true, + }, + }, + }; + } + // do nothing + return prev; + }); } }) .catch(() => { From 65f665f8fdb6839cae83d658644aff931f652b94 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:31:32 +0000 Subject: [PATCH 29/45] Refactor AppInfoProvider to conditionally render children based on appInfo --- frontend/context/AppInfoProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/context/AppInfoProvider.tsx b/frontend/context/AppInfoProvider.tsx index f052e1081..72490e7e8 100644 --- a/frontend/context/AppInfoProvider.tsx +++ b/frontend/context/AppInfoProvider.tsx @@ -31,7 +31,7 @@ export const AppInfoProvider = ({ children }: PropsWithChildren) => { return ( - {children} + {appInfo && children} ); }; From 0428f10cd6ad91e2dbf12ca49f4e8908e94b4034 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:31:42 +0000 Subject: [PATCH 30/45] Remove unused import and update default value for screen in SpawnProvider --- frontend/context/SpawnProvider/SpawnProvider.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/context/SpawnProvider/SpawnProvider.tsx b/frontend/context/SpawnProvider/SpawnProvider.tsx index 8cf503e4d..2281fe5a1 100644 --- a/frontend/context/SpawnProvider/SpawnProvider.tsx +++ b/frontend/context/SpawnProvider/SpawnProvider.tsx @@ -1,4 +1,3 @@ -import { SpawnScreen } from '@/enums'; import { SpawnData } from '@/types'; import { Dispatch, @@ -13,15 +12,13 @@ type SpawnContextType = { setSpawnData: Dispatch>; }; -const FIRST_SPAWN_SCREEN: SpawnScreen = SpawnScreen.RPC; - export const DEFAULT_SPAWN_DATA: SpawnData = { agentFundRequirements: {}, masterWalletFundRequirements: {}, isStaking: undefined, nativeBalance: undefined, rpc: '', - screen: FIRST_SPAWN_SCREEN, + screen: undefined, serviceTemplate: undefined, service: undefined, }; @@ -33,7 +30,6 @@ export const SpawnContext = createContext({ export const SpawnProvider = ({ children }: PropsWithChildren) => { const [spawnData, setSpawnData] = useState(DEFAULT_SPAWN_DATA); - return ( Date: Thu, 7 Mar 2024 19:31:49 +0000 Subject: [PATCH 31/45] Refactor useSpawn hook to load spawn data and get agent fund requirements --- frontend/hooks/useSpawn.tsx | 172 ++++++++++++++++++++++++------------ 1 file changed, 115 insertions(+), 57 deletions(-) diff --git a/frontend/hooks/useSpawn.tsx b/frontend/hooks/useSpawn.tsx index 76d05f06a..bc8dafac3 100644 --- a/frontend/hooks/useSpawn.tsx +++ b/frontend/hooks/useSpawn.tsx @@ -1,13 +1,55 @@ -import { Service } from '@/client'; +import { Service, ServiceTemplate } from '@/client'; import { DEFAULT_SPAWN_DATA, SpawnContext } from '@/context'; import { SpawnScreen } from '@/enums'; import { useCallback, useContext, useMemo } from 'react'; -import { Address, FundingRecord } from '@/types'; import { message } from 'antd'; import { ServicesService } from '@/service'; +import { useAppInfo, useServiceTemplates, useServices } from '.'; +import { Address, FundingRecord } from '@/types'; + +/** + * Generates agent fund requirements from valid service and service template + */ +const getAgentFundRequirements = ({ + serviceTemplate, + service, +}: { + serviceTemplate: ServiceTemplate; + service: Service; +}): FundingRecord | undefined => { + if (!serviceTemplate || !service?.chain_data.instances) return undefined; + + // Agent funding requirements + let agentFundRequirements: FundingRecord = {}; + + const required = serviceTemplate.configuration.fund_requirements.agent; + + agentFundRequirements = service.chain_data.instances.reduce( + (acc: FundingRecord, address: Address) => ({ + ...acc, + [address]: { + required, + received: false, + }, + }), + {}, + ); + + // Multisig funding requirements + if (service.chain_data?.multisig) { + const { multisig } = service.chain_data; + const { safe } = serviceTemplate.configuration.fund_requirements; + agentFundRequirements[multisig] = { required: safe, received: false }; + } + + return agentFundRequirements; +}; export const useSpawn = () => { const { spawnData, setSpawnData } = useContext(SpawnContext); + const { getServiceFromState } = useServices(); + const { getServiceTemplate } = useServiceTemplates(); + const { userPublicKey } = useAppInfo(); // MEMOS const spawnPercentage: number = useMemo(() => { @@ -49,7 +91,13 @@ export const useSpawn = () => { return; } - setSpawnData((prev) => ({ ...prev, service })); + const agentFundRequirements = getAgentFundRequirements({ + serviceTemplate: spawnData.serviceTemplate, + service, + }); + if (!agentFundRequirements) return; + + setSpawnData((prev) => ({ ...prev, service, agentFundRequirements })); return service; }, [setSpawnData, spawnData.rpc, spawnData.serviceTemplate], @@ -63,67 +111,77 @@ export const useSpawn = () => { ); /** - * Creates master wallet funding requirements in spawnData - */ - const createMasterWalletFundRequirements = useCallback(() => { - if (!spawnData.serviceTemplate) return; - - const required = 1; - - setSpawnData((prev) => ({ - ...prev, - masterWalletFundRequirements: { - required, - received: false, - }, - })); - }, [setSpawnData, spawnData.serviceTemplate]); - - /** - * Creates agent funding requirements in spawnData + * Call once to load spawn data */ - const createAgentFundRequirements = useCallback((): - | FundingRecord - | undefined => { - if (!spawnData.serviceTemplate || !spawnData.service?.chain_data.instances) - return undefined; - - // Agent funding requirements - let agentFundRequirements: FundingRecord = {}; - - const required = - spawnData.serviceTemplate.configuration.fund_requirements.agent; - - agentFundRequirements = spawnData.service.chain_data.instances.reduce( - (acc: FundingRecord, address: Address) => ({ - ...acc, - [address]: { - required, - received: false, - }, - }), - {}, - ); - - // Multisig funding requirements - if (spawnData.service.chain_data?.multisig) { - const { multisig } = spawnData.service.chain_data; - const { safe } = - spawnData.serviceTemplate.configuration.fund_requirements; - agentFundRequirements[multisig] = { required: safe, received: false }; - } - - setSpawnData((prev) => ({ ...prev, agentFundRequirements })); - }, [setSpawnData, spawnData.service, spawnData.serviceTemplate]); + const loadSpawn = useCallback( + ({ + serviceTemplateHash, + screen, + }: { + serviceTemplateHash: string; + screen: SpawnScreen | null | undefined; + }) => { + if (!userPublicKey) return; + try { + const serviceTemplate = getServiceTemplate(serviceTemplateHash); + if (!serviceTemplate) throw new Error('Service template not found'); + + if (screen && screen !== null) { + // Funding resume required + const service = getServiceFromState(serviceTemplateHash); + if (!service) throw new Error('Service not found'); + + const { + ledger: { rpc }, + } = service; + + const agentFundRequirements = getAgentFundRequirements({ + serviceTemplate, + service, + }); + + if (!agentFundRequirements) + throw new Error('Agent fund requirements not found'); + + setSpawnData((prev) => ({ + ...prev, + service, + serviceTemplate, + screen, + rpc, + masterWalletFundRequirements: { + [userPublicKey]: { required: 1, received: false }, + }, + agentFundRequirements, + })); + } else { + // No resume required + setSpawnData((prev) => ({ + ...prev, + serviceTemplate, + screen: SpawnScreen.RPC, + masterWalletFundRequirements: { + [userPublicKey]: { required: 1, received: false }, + }, + })); + } + } catch (e) { + setSpawnData((prev) => ({ + ...prev, + screen: SpawnScreen.ERROR, + })); + } + }, + [getServiceFromState, getServiceTemplate, setSpawnData, userPublicKey], + ); return { - ...spawnData, spawnData, spawnPercentage, + getAgentFundRequirements, createService, + loadSpawn, resetSpawn, setSpawnData, - createAgentFundRequirements, - createMasterWalletFundRequirements, }; }; From aca141e7bf80d749a2698713d9334ccf6694ab87 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:31:54 +0000 Subject: [PATCH 32/45] Refactor SpawnPage component to use new useSpawn hook --- .../pages/spawn/[serviceTemplateHash].tsx | 45 +++++-------------- 1 file changed, 11 insertions(+), 34 deletions(-) diff --git a/frontend/pages/spawn/[serviceTemplateHash].tsx b/frontend/pages/spawn/[serviceTemplateHash].tsx index ea6d63ccb..ed4946695 100644 --- a/frontend/pages/spawn/[serviceTemplateHash].tsx +++ b/frontend/pages/spawn/[serviceTemplateHash].tsx @@ -1,9 +1,9 @@ import { SpawnRPC } from '@/components/Spawn'; import { SpawnScreen } from '@/enums'; -import { useServices, useSpawn, useServiceTemplates } from '@/hooks'; +import { useSpawn } from '@/hooks'; import { GetServerSidePropsContext } from 'next'; import dynamic from 'next/dynamic'; -import { ReactElement, useEffect, useMemo } from 'react'; +import { ReactElement, useEffect, useMemo, useState } from 'react'; const SpawnAgentFunding = dynamic( () => @@ -57,40 +57,17 @@ type SpawnPageProps = { }; export const SpawnPage = (props: SpawnPageProps) => { - const { getServiceFromState } = useServices(); - const { getServiceTemplate } = useServiceTemplates(); - const { setSpawnData, spawnData } = useSpawn(); + const { loadSpawn, spawnData } = useSpawn(); + const [isLoaded, setIsLoaded] = useState(false); useEffect(() => { - try { - const serviceTemplate = getServiceTemplate(props.serviceTemplateHash); - if (!serviceTemplate) throw new Error('Service template not found'); - if (props.screen === null) { - // No resume required - setSpawnData((prev) => ({ ...prev, serviceTemplate })); - } else { - // Funding, resume required - const service = getServiceFromState(props.serviceTemplateHash); - if (!service) throw new Error('Service not found'); - const { - ledger: { rpc }, - } = service; - setSpawnData((prev) => ({ - ...prev, - serviceTemplate, - screen: props.screen as SpawnScreen, // cast required though it's not null; TS doesn't not support typeof or instanceof for enum - rpc, - })); - } - } catch (e) { - setSpawnData((prev) => ({ - ...prev, - screen: SpawnScreen.ERROR, - })); - } - // Runs once, no deps required as it will reset "screen" state attribute - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + if (isLoaded) return; + loadSpawn({ + serviceTemplateHash: props.serviceTemplateHash, + screen: props.screen, + }); + setIsLoaded(true); + }, [isLoaded, loadSpawn, props.screen, props.serviceTemplateHash, spawnData]); const spawnScreen: ReactElement = useMemo(() => { switch (spawnData.screen) { From ce7b226e62d8a7ebc454c655baa87c99f8fdd435 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:31:58 +0000 Subject: [PATCH 33/45] Update screen property in SpawnData.ts --- frontend/types/SpawnData.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/types/SpawnData.ts b/frontend/types/SpawnData.ts index 65fccd22c..51606126c 100644 --- a/frontend/types/SpawnData.ts +++ b/frontend/types/SpawnData.ts @@ -8,7 +8,7 @@ export type SpawnData = { isStaking?: boolean; nativeBalance?: number; rpc: string; - screen: SpawnScreen; + screen?: SpawnScreen; serviceTemplate?: ServiceTemplate; service?: Service; }; From c4a6f85827d9e42e9faa1832bd9a9d72f45acf9c Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:44:27 +0000 Subject: [PATCH 34/45] Update import statement for EthersService in SpawnMasterWalletFunding component --- frontend/components/Spawn/SpawnMasterWalletFunding.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/Spawn/SpawnMasterWalletFunding.tsx b/frontend/components/Spawn/SpawnMasterWalletFunding.tsx index 8f19e43d5..b278bfd64 100644 --- a/frontend/components/Spawn/SpawnMasterWalletFunding.tsx +++ b/frontend/components/Spawn/SpawnMasterWalletFunding.tsx @@ -4,7 +4,7 @@ import { FundRequirementETH } from './Funding/FundRequirement/FundRequirementETH import { useAppInfo, useSpawn } from '@/hooks'; import { useEffect, useState } from 'react'; import { Spin } from 'antd'; -import EthersService from '@/service/Ethers'; +import { EthersService } from '@/service'; export const SpawnMasterWalletFunding = ({ nextPage, From a5e9fabf3397e83ee593a05a1757eb349c975bb4 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:44:32 +0000 Subject: [PATCH 35/45] Update EthersService import in SpawnRPC.tsx --- frontend/components/Spawn/SpawnRPC.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/Spawn/SpawnRPC.tsx b/frontend/components/Spawn/SpawnRPC.tsx index 257151bfd..3b2cbc560 100644 --- a/frontend/components/Spawn/SpawnRPC.tsx +++ b/frontend/components/Spawn/SpawnRPC.tsx @@ -14,7 +14,7 @@ import { useSpawn, useAppInfo } from '@/hooks'; import { CheckSquareTwoTone, WarningFilled } from '@ant-design/icons'; import { InputStatus } from 'antd/es/_util/statusUtils'; import { debounce } from 'lodash'; -import EthersService from '@/service/Ethers'; +import { EthersService } from '@/service'; import { SpawnScreen } from '@/enums'; enum RPCState { From 072e7eb308acac09a582a28195e73d01aa844bd4 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:44:35 +0000 Subject: [PATCH 36/45] Update EthersService import in SpawnStakingCheck component --- frontend/components/Spawn/SpawnStakingCheck.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/Spawn/SpawnStakingCheck.tsx b/frontend/components/Spawn/SpawnStakingCheck.tsx index a0c660018..30751b3a8 100644 --- a/frontend/components/Spawn/SpawnStakingCheck.tsx +++ b/frontend/components/Spawn/SpawnStakingCheck.tsx @@ -2,7 +2,7 @@ import { Service } from '@/client'; import { TOKENS } from '@/constants'; import { SpawnScreen } from '@/enums'; import { useAppInfo, useSpawn } from '@/hooks'; -import EthersService from '@/service/Ethers'; +import { EthersService } from '@/service'; import { Button, Flex, Skeleton, Typography, message } from 'antd'; import { ethers } from 'ethers'; import { useCallback, useMemo, useState } from 'react'; From ac6738adbbb26a1fb53a608165552524feea320c Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:44:39 +0000 Subject: [PATCH 37/45] Refactor imports in ServiceCard.tsx --- frontend/components/YourAgents/ServiceCard/ServiceCard.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx b/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx index 410b9591b..e0479cbec 100644 --- a/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx +++ b/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx @@ -26,8 +26,7 @@ import { SERVICE_CARD_RPC_POLLING_INTERVAL, SERVICE_CARD_STATUS_POLLING_INTERVAL, } from '@/constants/intervals'; -import EthersService from '@/service/Ethers'; -import { ServicesService } from '@/service'; +import { ServicesService, EthersService } from '@/service'; type ServiceCardProps = { service: Service; From 8f65a160fd7159fbf975250097289fc436a391c9 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:44:43 +0000 Subject: [PATCH 38/45] Export EthersService in Ethers.ts --- frontend/service/Ethers.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/service/Ethers.ts b/frontend/service/Ethers.ts index 56197a6a6..4933adc5b 100644 --- a/frontend/service/Ethers.ts +++ b/frontend/service/Ethers.ts @@ -87,10 +87,8 @@ const checkRpc = async (rpc: string): Promise => { } }; -const EthersService = { +export const EthersService = { getEthBalance, getErc20Balance, checkRpc, }; - -export default EthersService; From 088beec16bba6c55daf78c6531e7694082cbb096 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 19:44:47 +0000 Subject: [PATCH 39/45] Add Ethers and Multicall services --- frontend/service/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/service/index.ts b/frontend/service/index.ts index 341c136cd..a8e95c1ce 100644 --- a/frontend/service/index.ts +++ b/frontend/service/index.ts @@ -1,2 +1,4 @@ export * from './AppInfo'; export * from './Services'; +export * from './Ethers'; +export * from './Multicall'; From 32ec04dce3a8543ecbb50a19e966e02dd87ef756 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 20:06:18 +0000 Subject: [PATCH 40/45] Update Navbar and ServiceCard components --- frontend/components/Layout/Navbar/Navbar.tsx | 6 ---- .../YourAgents/ServiceCard/ServiceCard.tsx | 8 ++++- .../ServiceCard/ServiceCardSettings.tsx | 36 +++++++++++++++++++ frontend/package.json | 7 ++-- frontend/yarn.lock | 11 +++++- package.json | 5 +-- yarn.lock | 9 ++++- 7 files changed, 68 insertions(+), 14 deletions(-) create mode 100644 frontend/components/YourAgents/ServiceCard/ServiceCardSettings.tsx diff --git a/frontend/components/Layout/Navbar/Navbar.tsx b/frontend/components/Layout/Navbar/Navbar.tsx index bfd42b50a..dc420dbd7 100644 --- a/frontend/components/Layout/Navbar/Navbar.tsx +++ b/frontend/components/Layout/Navbar/Navbar.tsx @@ -1,16 +1,10 @@ import { Flex } from 'antd'; -import { SettingsButton } from './SettingsButton'; -import { NotificationButton } from './NotificationButton'; import Image from 'next/image'; export const Navbar = () => { return ( - - - - ); }; diff --git a/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx b/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx index e0479cbec..aaeaba563 100644 --- a/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx +++ b/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx @@ -8,6 +8,7 @@ import { message, Tooltip, } from 'antd'; +import { green } from '@ant-design/colors'; import Image from 'next/image'; import { useCallback, useMemo, useState } from 'react'; import { useInterval } from 'usehooks-ts'; @@ -27,6 +28,7 @@ import { SERVICE_CARD_STATUS_POLLING_INTERVAL, } from '@/constants/intervals'; import { ServicesService, EthersService } from '@/service'; +import { ServiceCardSettings } from './ServiceCardSettings'; type ServiceCardProps = { service: Service; @@ -195,6 +197,8 @@ export const ServiceCard = ({ service }: ServiceCardProps) => { )} + + ; case DeploymentStatus.DEPLOYED: - return ; + return ( + + ); // processing status adds pulse animation; color prop is used to override the default color case DeploymentStatus.STOPPING: return ; case DeploymentStatus.STOPPED: diff --git a/frontend/components/YourAgents/ServiceCard/ServiceCardSettings.tsx b/frontend/components/YourAgents/ServiceCard/ServiceCardSettings.tsx new file mode 100644 index 000000000..93eb19762 --- /dev/null +++ b/frontend/components/YourAgents/ServiceCard/ServiceCardSettings.tsx @@ -0,0 +1,36 @@ +import { SpawnScreen } from '@/enums'; +import { SettingOutlined } from '@ant-design/icons'; +import { Button, Dropdown, MenuProps } from 'antd'; +import Link from 'next/link'; +import { useMemo } from 'react'; + +export const ServiceCardSettings = ({ + serviceHash, +}: { + serviceHash: string; +}) => { + const items: MenuProps['items'] = useMemo( + () => [ + { + key: '1', + label: ( + + Fund agent + + ), + }, + { key: '2', label: Delete Agent, danger: true }, + ], + [serviceHash], + ); + + return ( + + + + ); +}; diff --git a/frontend/package.json b/frontend/package.json index e6bccd236..59d264daa 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,8 @@ { "author": "Valory AG", "dependencies": { + "@ant-design/colors": "^7.0.2", + "@ant-design/cssinjs": "^1.18.4", "@ant-design/icons": "^5.3.0", "antd": "^5.14.0", "ethers": "5.7.2", @@ -8,10 +10,9 @@ "next": "14.1.0", "react": "^18", "react-dom": "^18", + "sudo-prompt": "9.2.1", "swr": "^2.2.4", - "usehooks-ts": "^2.14.0", - "@ant-design/cssinjs": "^1.18.4", - "sudo-prompt": "9.2.1" + "usehooks-ts": "^2.14.0" }, "devDependencies": { "@testing-library/jest-dom": "^6.4.2", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 27a17a503..657435aab 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -20,13 +20,20 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@ant-design/colors@^7.0.0", "@ant-design/colors@^7.0.2": +"@ant-design/colors@^7.0.0": version "7.0.2" resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.2.tgz" integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== dependencies: "@ctrl/tinycolor" "^3.6.1" +"@ant-design/colors@^7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-7.0.2.tgz#c5c753a467ce8d86ba7ca4736d2c01f599bb5492" + integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== + dependencies: + "@ctrl/tinycolor" "^3.6.1" + "@ant-design/cssinjs@^1.18.4": version "1.18.4" resolved "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.18.4.tgz" @@ -5436,6 +5443,7 @@ string-length@^4.0.1: strip-ansi "^6.0.0" "string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + name string-width-cjs version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5946,6 +5954,7 @@ which@^2.0.1: isexe "^2.0.0" "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: + name wrap-ansi-cjs version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== diff --git a/package.json b/package.json index 486f9b317..c034d142f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "author": "Valory AG", "dependencies": { + "@ant-design/colors": "^7.0.2", "@ant-design/cssinjs": "^1.18.4", "@ant-design/icons": "^5.3.0", "antd": "^5.14.0", @@ -16,9 +17,9 @@ "ps-tree": "^1.2.0", "react": "^18", "react-dom": "^18", + "sudo-prompt": "9.2.1", "swr": "^2.2.4", - "usehooks-ts": "^2.14.0", - "sudo-prompt": "9.2.1" + "usehooks-ts": "^2.14.0" }, "devDependencies": { "concurrently": "^8.2.2", diff --git a/yarn.lock b/yarn.lock index 9006ba3d6..08bb583c2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,13 +12,20 @@ resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@ant-design/colors@^7.0.0", "@ant-design/colors@^7.0.2": +"@ant-design/colors@^7.0.0": version "7.0.2" resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.2.tgz" integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== dependencies: "@ctrl/tinycolor" "^3.6.1" +"@ant-design/colors@^7.0.2": + version "7.0.2" + resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-7.0.2.tgz#c5c753a467ce8d86ba7ca4736d2c01f599bb5492" + integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== + dependencies: + "@ctrl/tinycolor" "^3.6.1" + "@ant-design/cssinjs@^1.18.4": version "1.18.4" resolved "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.18.4.tgz" From 53dcee486c3ab21bf5413030368d7860faaa2d28 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Thu, 7 Mar 2024 21:12:40 +0000 Subject: [PATCH 41/45] Update service imports and add checkServiceIsFunded function --- .../FundRequirement/FundRequirementERC20.tsx | 2 +- .../FundRequirement/FundRequirementETH.tsx | 2 +- .../components/Spawn/SpawnAgentFunding.tsx | 49 +++++++++++++- .../YourAgents/ServiceCard/ServiceCard.tsx | 39 ++++++----- .../ServiceCard/ServiceCardSettings.tsx | 64 ++++++++++++++++--- frontend/hooks/useServices.tsx | 39 ++++++++++- 6 files changed, 161 insertions(+), 34 deletions(-) diff --git a/frontend/components/Spawn/Funding/FundRequirement/FundRequirementERC20.tsx b/frontend/components/Spawn/Funding/FundRequirement/FundRequirementERC20.tsx index a8f309b5d..e509dffae 100644 --- a/frontend/components/Spawn/Funding/FundRequirement/FundRequirementERC20.tsx +++ b/frontend/components/Spawn/Funding/FundRequirement/FundRequirementERC20.tsx @@ -1,7 +1,7 @@ import { Dispatch, SetStateAction } from 'react'; import { FundRequirement } from './FundRequirement'; import { Address, SpawnData } from '@/types'; -import EthersService from '@/service/Ethers'; +import { EthersService } from '@/service'; type FundRequirementERC20Props = { address: Address; diff --git a/frontend/components/Spawn/Funding/FundRequirement/FundRequirementETH.tsx b/frontend/components/Spawn/Funding/FundRequirement/FundRequirementETH.tsx index 69b0f4c75..d827023b1 100644 --- a/frontend/components/Spawn/Funding/FundRequirement/FundRequirementETH.tsx +++ b/frontend/components/Spawn/Funding/FundRequirement/FundRequirementETH.tsx @@ -1,7 +1,7 @@ import { Dispatch, SetStateAction } from 'react'; import { FundRequirement } from './FundRequirement'; import { Address, SpawnData } from '@/types'; -import EthersService from '@/service/Ethers'; +import { EthersService } from '@/service'; type FundRequirementETHProps = { address: Address; diff --git a/frontend/components/Spawn/SpawnAgentFunding.tsx b/frontend/components/Spawn/SpawnAgentFunding.tsx index 4f4de6793..9863a1a80 100644 --- a/frontend/components/Spawn/SpawnAgentFunding.tsx +++ b/frontend/components/Spawn/SpawnAgentFunding.tsx @@ -1,7 +1,11 @@ import { Funding } from './Funding/Funding'; import { SpawnScreen } from '@/enums'; import { FundRequirementETH } from './Funding/FundRequirement/FundRequirementETH'; -import { useSpawn } from '@/hooks'; +import { useAppInfo, useSpawn } from '@/hooks'; +import { Spin } from 'antd'; +import { useState, useEffect } from 'react'; +import MulticallService from '@/service/Multicall'; +import { Address, AddressNumberRecord } from '@/types'; type SpawnAgentFundingProps = { nextPage: SpawnScreen; @@ -9,11 +13,50 @@ type SpawnAgentFundingProps = { export const SpawnAgentFunding = (props: SpawnAgentFundingProps) => { const { - spawnData: { agentFundRequirements: fundRequirements }, + setSpawnData, + spawnData: { rpc, agentFundRequirements }, } = useSpawn(); + const { userPublicKey } = useAppInfo(); + const [isInitialLoaded, setIsInitialLoaded] = useState(false); + + useEffect(() => { + if (!isInitialLoaded && userPublicKey) { + const agentAddresses = Object.keys(agentFundRequirements) as Address[]; + MulticallService.getEthBalances(agentAddresses, rpc).then( + (balances: AddressNumberRecord) => { + setSpawnData((prev) => ({ + ...prev, + agentFundRequirements: agentAddresses.reduce( + (acc, address) => ({ + ...acc, + [address]: { + ...agentFundRequirements[address], + received: balances[address] > 1, + }, + }), + {}, + ), + })); + setIsInitialLoaded(true); + }, + ); + } + }, [ + agentFundRequirements, + isInitialLoaded, + rpc, + setSpawnData, + userPublicKey, + ]); + + // if not inital loaded, show loader + if (agentFundRequirements === undefined || !isInitialLoaded) { + return ; + } + return ( { - const { - stopService, - deployService, - deleteServices, - getServiceStatus, - deleteServiceState, - } = useServices(); + const { deleteServiceState } = useServices(); const { getServiceTemplate } = useServiceTemplates(); const [serviceStatus, setServiceStatus] = useState< @@ -107,10 +101,12 @@ export const ServiceCard = ({ service }: ServiceCardProps) => { if (isDeleting) return; setIsDeleting(true); ServicesService.deleteServices({ hashes: [service.hash] }) - .catch(() => message.error('Failed to delete service')) - .finally(() => { + .then(() => { + message.success('Service deleted successfully'); deleteServiceState(service.hash); - }); + }) + .catch(() => message.error('Failed to delete service')) + .finally(() => setIsDeleting(false)); }, [deleteServiceState, isDeleting, service.hash]); const buttons = useMemo( @@ -132,10 +128,10 @@ export const ServiceCard = ({ service }: ServiceCardProps) => { <> Are you sure you want to delete this service?
- Your agent's private keys will be lost. + Your funds may be lost. } - placement="leftBottom" + placement="topLeft" onConfirm={handleDelete} > diff --git a/frontend/hooks/useServices.tsx b/frontend/hooks/useServices.tsx index 2dd95b106..8cf79a9c5 100644 --- a/frontend/hooks/useServices.tsx +++ b/frontend/hooks/useServices.tsx @@ -1,8 +1,44 @@ -import { Service, ServiceHash } from '@/client'; +import { Service, ServiceHash, ServiceTemplate } from '@/client'; import { ServicesContext } from '@/context'; import { ServicesService } from '@/service'; +import MulticallService from '@/service/Multicall'; +import { Address, AddressBooleanRecord } from '@/types'; import { useContext } from 'react'; +const checkServiceIsFunded = async ( + service: Service, + serviceTemplate: ServiceTemplate, +): Promise => { + const { + chain_data: { instances, multisig }, + } = service; + + if (!instances || !multisig) return Promise.resolve(false); + + const addresses = [...instances, multisig]; + + const balances = await MulticallService.getEthBalances( + addresses, + service.ledger.rpc, + ); + + if (!balances) return Promise.resolve(false); + + const fundRequirements: AddressBooleanRecord = addresses.reduce( + (acc: AddressBooleanRecord, address: Address) => ({ + ...acc, + [address]: instances.includes(address) + ? balances[address] > + serviceTemplate.configuration.fund_requirements.agent + : balances[address] > + serviceTemplate.configuration.fund_requirements.safe, + }), + {}, + ); + + return Promise.resolve(Object.values(fundRequirements).every((f) => f)); +}; + export const useServices = () => { const { services, updateServicesState, hasInitialLoaded, setServices } = useContext(ServicesContext); @@ -37,6 +73,7 @@ export const useServices = () => { return { getServiceFromState, getServicesFromState, + checkServiceIsFunded, updateServicesState, updateServiceState, deleteServiceState, From c69ef3279e51a3e13c3307b88c40f8d714ada955 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Fri, 8 Mar 2024 11:38:45 +0000 Subject: [PATCH 42/45] fix unneeded condition --- frontend/hooks/useSpawn.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/useSpawn.tsx b/frontend/hooks/useSpawn.tsx index bc8dafac3..006b282ae 100644 --- a/frontend/hooks/useSpawn.tsx +++ b/frontend/hooks/useSpawn.tsx @@ -126,7 +126,7 @@ export const useSpawn = () => { const serviceTemplate = getServiceTemplate(serviceTemplateHash); if (!serviceTemplate) throw new Error('Service template not found'); - if (screen && screen !== null) { + if (screen) { // Funding resume required const service = getServiceFromState(serviceTemplateHash); if (!service) throw new Error('Service not found'); From b6b65e0ac3296d4d4cf61e45cc219bea1a2e643c Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Fri, 8 Mar 2024 11:39:54 +0000 Subject: [PATCH 43/45] remove return undefined --- frontend/hooks/useSpawn.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/useSpawn.tsx b/frontend/hooks/useSpawn.tsx index 006b282ae..a554fd3dd 100644 --- a/frontend/hooks/useSpawn.tsx +++ b/frontend/hooks/useSpawn.tsx @@ -17,7 +17,7 @@ const getAgentFundRequirements = ({ serviceTemplate: ServiceTemplate; service: Service; }): FundingRecord | undefined => { - if (!serviceTemplate || !service?.chain_data.instances) return undefined; + if (!serviceTemplate || !service?.chain_data.instances) return; // Agent funding requirements let agentFundRequirements: FundingRecord = {}; From a5a2b9a3576856440c8ec8b9eb8a2cc059f09384 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Fri, 8 Mar 2024 12:11:45 +0000 Subject: [PATCH 44/45] fixes as per comments --- .../components/Spawn/SpawnAgentFunding.tsx | 41 +++++++++---------- .../Spawn/SpawnMasterWalletFunding.tsx | 26 ++++++------ .../components/Spawn/SpawnStakingCheck.tsx | 40 ++++++------------ .../ServiceCard/ServiceCardSettings.tsx | 2 +- frontend/hooks/useSpawn.tsx | 6 +-- 5 files changed, 48 insertions(+), 67 deletions(-) diff --git a/frontend/components/Spawn/SpawnAgentFunding.tsx b/frontend/components/Spawn/SpawnAgentFunding.tsx index 9863a1a80..ef9c1ba47 100644 --- a/frontend/components/Spawn/SpawnAgentFunding.tsx +++ b/frontend/components/Spawn/SpawnAgentFunding.tsx @@ -20,27 +20,26 @@ export const SpawnAgentFunding = (props: SpawnAgentFundingProps) => { const [isInitialLoaded, setIsInitialLoaded] = useState(false); useEffect(() => { - if (!isInitialLoaded && userPublicKey) { - const agentAddresses = Object.keys(agentFundRequirements) as Address[]; - MulticallService.getEthBalances(agentAddresses, rpc).then( - (balances: AddressNumberRecord) => { - setSpawnData((prev) => ({ - ...prev, - agentFundRequirements: agentAddresses.reduce( - (acc, address) => ({ - ...acc, - [address]: { - ...agentFundRequirements[address], - received: balances[address] > 1, - }, - }), - {}, - ), - })); - setIsInitialLoaded(true); - }, - ); - } + if (!(!isInitialLoaded && userPublicKey)) return; + const agentAddresses = Object.keys(agentFundRequirements) as Address[]; + MulticallService.getEthBalances(agentAddresses, rpc).then( + (balances: AddressNumberRecord) => { + setSpawnData((prev) => ({ + ...prev, + agentFundRequirements: agentAddresses.reduce( + (acc, address) => ({ + ...acc, + [address]: { + ...agentFundRequirements[address], + received: balances[address] > 1, + }, + }), + {}, + ), + })); + setIsInitialLoaded(true); + }, + ); }, [ agentFundRequirements, isInitialLoaded, diff --git a/frontend/components/Spawn/SpawnMasterWalletFunding.tsx b/frontend/components/Spawn/SpawnMasterWalletFunding.tsx index b278bfd64..5eed88f23 100644 --- a/frontend/components/Spawn/SpawnMasterWalletFunding.tsx +++ b/frontend/components/Spawn/SpawnMasterWalletFunding.tsx @@ -3,7 +3,7 @@ import { Funding } from './Funding/Funding'; import { FundRequirementETH } from './Funding/FundRequirement/FundRequirementETH'; import { useAppInfo, useSpawn } from '@/hooks'; import { useEffect, useState } from 'react'; -import { Spin } from 'antd'; +import { Spin, message } from 'antd'; import { EthersService } from '@/service'; export const SpawnMasterWalletFunding = ({ @@ -20,18 +20,20 @@ export const SpawnMasterWalletFunding = ({ useEffect(() => { if (!isInitialLoaded && userPublicKey) { - EthersService.getEthBalance(userPublicKey, rpc).then((balance) => { - setSpawnData((prev) => ({ - ...prev, - masterWalletFundRequirements: { - [userPublicKey]: { - ...prev.masterWalletFundRequirements[userPublicKey], - received: balance > 1, + EthersService.getEthBalance(userPublicKey, rpc) + .then((balance) => { + setSpawnData((prev) => ({ + ...prev, + masterWalletFundRequirements: { + [userPublicKey]: { + ...prev.masterWalletFundRequirements[userPublicKey], + received: balance > 1, + }, }, - }, - })); - setIsInitialLoaded(true); - }); + })); + setIsInitialLoaded(true); + }) + .catch(() => message.error('Failed to get master wallet balance')); } }, [ isInitialLoaded, diff --git a/frontend/components/Spawn/SpawnStakingCheck.tsx b/frontend/components/Spawn/SpawnStakingCheck.tsx index 30751b3a8..53a4ba82f 100644 --- a/frontend/components/Spawn/SpawnStakingCheck.tsx +++ b/frontend/components/Spawn/SpawnStakingCheck.tsx @@ -30,7 +30,7 @@ export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { /** * Creates service, then performs relevant state updates */ - const create = useCallback( + const createAndNext = useCallback( async ({ isStaking }: { isStaking: boolean }) => { if (isCreating) { message.error('Service creation already in progress'); @@ -42,13 +42,20 @@ export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { try { const service: Service | undefined = await createService(isStaking); if (!service) throw new Error('Failed to create service'); + message.success('Service created successfully'); + setSpawnData((prev) => ({ + ...prev, + isStaking, + screen: nextPage, + })); } catch (e) { message.error('Failed to create service'); } finally { setIsCreating(false); + setButtonClicked(undefined); } }, - [createService, isCreating], + [createService, isCreating, nextPage, setSpawnData], ); /** @@ -86,8 +93,6 @@ export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { const handleYes = async () => { setButtonClicked(ButtonOptions.YES); - const isStaking = true; - const canStake: boolean = await preflightStakingCheck().catch((e) => { message.error(e); return false; @@ -98,37 +103,16 @@ export const SpawnStakingCheck = ({ nextPage }: SpawnStakingCheckProps) => { return setButtonClicked(undefined); } - create({ isStaking }) - .then(() => { - message.success('Service created successfully'); - setSpawnData((prev) => ({ - ...prev, - isStaking, - screen: nextPage, - })); - }) - .catch(() => setButtonClicked(undefined)); + createAndNext({ isStaking: true }); }; const handleNo = async () => { setButtonClicked(ButtonOptions.NO); - - const isStaking = false; - - create({ isStaking }) - .then(() => { - message.success('Service created successfully'); - setSpawnData((prev) => ({ - ...prev, - isStaking, - screen: nextPage, - })); - }) - .catch(() => setButtonClicked(undefined)); + createAndNext({ isStaking: false }); }; const stakingRequirement: string | undefined = useMemo(() => { - if (!serviceTemplate?.configuration) return undefined; + if (!serviceTemplate?.configuration) return; const { olas_required_to_stake, olas_cost_of_bond } = serviceTemplate.configuration; return ethers.utils.formatUnits( diff --git a/frontend/components/YourAgents/ServiceCard/ServiceCardSettings.tsx b/frontend/components/YourAgents/ServiceCard/ServiceCardSettings.tsx index 05af62763..6a8158956 100644 --- a/frontend/components/YourAgents/ServiceCard/ServiceCardSettings.tsx +++ b/frontend/components/YourAgents/ServiceCard/ServiceCardSettings.tsx @@ -20,7 +20,7 @@ export const ServiceCardSettings = ({ isLoading: boolean; }) => { const { deleteServiceState, checkServiceIsFunded } = useServices(); - const [isServiceFunded, setIsServiceFunded] = useState(true); + const [isServiceFunded, setIsServiceFunded] = useState(true); const handleDelete = useCallback(() => { ServicesService.deleteServices({ hashes: [service.hash] }) diff --git a/frontend/hooks/useSpawn.tsx b/frontend/hooks/useSpawn.tsx index a554fd3dd..0157d1ae2 100644 --- a/frontend/hooks/useSpawn.tsx +++ b/frontend/hooks/useSpawn.tsx @@ -27,10 +27,7 @@ const getAgentFundRequirements = ({ agentFundRequirements = service.chain_data.instances.reduce( (acc: FundingRecord, address: Address) => ({ ...acc, - [address]: { - required, - received: false, - }, + [address]: { required, received: false }, }), {}, ); @@ -68,7 +65,6 @@ export const useSpawn = () => { } }, [spawnData.screen]); - // METHODS const createService = useCallback( async (useStaking: boolean): Promise => { if (!spawnData.serviceTemplate || !spawnData.rpc) { From 11240e129b56074dbbc5b7abc35a6a23996f5bb3 Mon Sep 17 00:00:00 2001 From: Josh Miller Date: Fri, 8 Mar 2024 14:35:00 +0000 Subject: [PATCH 45/45] Update dependencies and fix color imports --- frontend/components/Spawn/Funding/Funding.tsx | 8 +++++--- .../components/YourAgents/ServiceCard/ServiceCard.tsx | 7 +++---- frontend/package.json | 1 - frontend/yarn.lock | 9 +-------- package.json | 1 - yarn.lock | 9 +-------- 6 files changed, 10 insertions(+), 25 deletions(-) diff --git a/frontend/components/Spawn/Funding/Funding.tsx b/frontend/components/Spawn/Funding/Funding.tsx index 189c62e33..c2bc46528 100644 --- a/frontend/components/Spawn/Funding/Funding.tsx +++ b/frontend/components/Spawn/Funding/Funding.tsx @@ -1,8 +1,7 @@ -import { COLOR } from '@/constants'; import { SpawnScreen } from '@/enums'; import { useSpawn } from '@/hooks'; import { Address, FundingRecord, SpawnData } from '@/types'; -import { TimelineItemProps, Flex, Typography, Timeline } from 'antd'; +import { TimelineItemProps, Flex, Typography, Timeline, theme } from 'antd'; import { isEmpty } from 'lodash'; import { useMemo, @@ -45,6 +44,7 @@ export const Funding = ({ setSpawnData, spawnData: { rpc }, } = useSpawn(); + const { token } = theme.useToken(); const timelineItems: TimelineItemProps[] = useMemo( () => @@ -62,7 +62,7 @@ export const Funding = ({ rpc={rpc} /> ), - color: received ? COLOR.GREEN_2 : COLOR.RED, + color: received ? token.green : token.red, }; }) as TimelineItemProps[], [ @@ -72,6 +72,8 @@ export const Funding = ({ rpc, setSpawnData, symbol, + token.green, + token.red, ], ); diff --git a/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx b/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx index 262729f5f..8d86d409c 100644 --- a/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx +++ b/frontend/components/YourAgents/ServiceCard/ServiceCard.tsx @@ -8,8 +8,8 @@ import { message, Tooltip, Popconfirm, + theme, } from 'antd'; -import { green } from '@ant-design/colors'; import Image from 'next/image'; import { useCallback, useMemo, useState } from 'react'; import { useInterval } from 'usehooks-ts'; @@ -223,6 +223,7 @@ const ServiceCardStatusBadge = ({ }: { serviceStatus?: DeploymentStatus; }) => { + const { token } = theme.useToken(); const badge = useMemo(() => { switch (serviceStatus) { case DeploymentStatus.CREATED: @@ -232,9 +233,7 @@ const ServiceCardStatusBadge = ({ case DeploymentStatus.DEPLOYING: return ; case DeploymentStatus.DEPLOYED: - return ( - - ); // processing status adds pulse animation; color prop is used to override the default color + return ; // processing status adds pulse animation; color prop is used to override the default color case DeploymentStatus.STOPPING: return ; case DeploymentStatus.STOPPED: diff --git a/frontend/package.json b/frontend/package.json index 59d264daa..98c6b0f0d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,6 @@ { "author": "Valory AG", "dependencies": { - "@ant-design/colors": "^7.0.2", "@ant-design/cssinjs": "^1.18.4", "@ant-design/icons": "^5.3.0", "antd": "^5.14.0", diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 657435aab..a6f81ff83 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -20,20 +20,13 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@ant-design/colors@^7.0.0": +"@ant-design/colors@^7.0.0", "@ant-design/colors@^7.0.2": version "7.0.2" resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.2.tgz" integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== dependencies: "@ctrl/tinycolor" "^3.6.1" -"@ant-design/colors@^7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-7.0.2.tgz#c5c753a467ce8d86ba7ca4736d2c01f599bb5492" - integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== - dependencies: - "@ctrl/tinycolor" "^3.6.1" - "@ant-design/cssinjs@^1.18.4": version "1.18.4" resolved "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.18.4.tgz" diff --git a/package.json b/package.json index c034d142f..ca8d186cc 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,6 @@ { "author": "Valory AG", "dependencies": { - "@ant-design/colors": "^7.0.2", "@ant-design/cssinjs": "^1.18.4", "@ant-design/icons": "^5.3.0", "antd": "^5.14.0", diff --git a/yarn.lock b/yarn.lock index 08bb583c2..9006ba3d6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12,20 +12,13 @@ resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@ant-design/colors@^7.0.0": +"@ant-design/colors@^7.0.0", "@ant-design/colors@^7.0.2": version "7.0.2" resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.2.tgz" integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== dependencies: "@ctrl/tinycolor" "^3.6.1" -"@ant-design/colors@^7.0.2": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-7.0.2.tgz#c5c753a467ce8d86ba7ca4736d2c01f599bb5492" - integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== - dependencies: - "@ctrl/tinycolor" "^3.6.1" - "@ant-design/cssinjs@^1.18.4": version "1.18.4" resolved "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.18.4.tgz"