From 43909504dfd33a9ce7c076a15ce76c386c0b3490 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Wed, 2 Apr 2025 12:36:51 +0400 Subject: [PATCH 01/44] release: 0.2.0-rc257 --- package.json | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ba48b9c62..49e52307b 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "start:frontend": "cd frontend && yarn start", "test:frontend": "cd frontend && yarn test" }, - "version": "0.2.0-rc256", + "version": "0.2.0-rc257", "engine": { "node": ">=20", "yarn": ">=1.22.0", diff --git a/pyproject.toml b/pyproject.toml index bafd5cd00..f2789805b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-app" -version = "0.2.0-rc256" +version = "0.2.0-rc257" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From 48026765ac190252af5771fed1efe4e510af478f Mon Sep 17 00:00:00 2001 From: Atatakai Date: Tue, 15 Apr 2025 19:15:13 +0400 Subject: [PATCH 02/44] release: 0.2.0-rc258 --- package.json | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 49e52307b..8455bc613 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "start:frontend": "cd frontend && yarn start", "test:frontend": "cd frontend && yarn test" }, - "version": "0.2.0-rc257", + "version": "0.2.0-rc258", "engine": { "node": ">=20", "yarn": ">=1.22.0", diff --git a/pyproject.toml b/pyproject.toml index 5b2680e85..3d95df8ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-app" -version = "0.2.0-rc257" +version = "0.2.0-rc258" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From 1e9b6f94027ee7afa990d15490252fbb9ec0610e Mon Sep 17 00:00:00 2001 From: Mohan Date: Thu, 8 May 2025 13:42:38 +0530 Subject: [PATCH 03/44] feat: Optimus agent init (#879) * feat: add Optimus agent type and service template * feat: add Optimus agent type and onboarding steps * feat: add Optimism staking programs and activity checkers * feat: update Optimus onboarding steps to include Uniswap and clarify investment requirements * feat: enhance Optimus staking program integration with updated contracts and configurations * feat: Refactor staking program identifiers to use consistent naming convention * feat: update Optimism staking program identifiers for consistency and clarity * feat: add Optimus agent form and update related components for integration * feat: enhance middleware enums and update Optimus configurations for clarity and consistency * feat: remove deprecated agent templates for cleaner configuration management * feat: update Optimus service template and related configurations for clarity and accuracy * Update frontend/config/chains.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: update middleware enums and service templates for clarity and consistency * feat: enhance service validation and update configurations for Optimism * chore: address review changes --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- frontend/client/enums.ts | 20 +- frontend/client/types.ts | 4 +- .../LowFunds/FundsToActivate.tsx | 6 +- .../StakingContractSection/MigrateButton.tsx | 6 +- .../AgentIntroduction/AgentIntroduction.tsx | 2 + .../SetupPage/AgentIntroduction/constants.ts | 18 ++ .../ModiusAgentForm/ModiusAgentForm.tsx | 16 +- .../OptimusAgentForm/OptimusAgentForm.tsx | 214 +++++++++++++++ .../useOptimusFormValidate.ts | 58 ++++ .../SetupYourAgent/SetupYourAgent.tsx | 5 +- .../SetupYourAgent/shared/formUtils.ts | 2 +- .../{ModiusAgentForm => shared}/labels.tsx | 21 +- .../UpdateAgentPage/ModiusUpdateForm.tsx | 26 +- .../UpdateAgentPage/OptimusUpdateForm.tsx | 202 ++++++++++++++ frontend/components/UpdateAgentPage/index.tsx | 2 + .../components/YourWalletPage/YourAgent.tsx | 3 +- frontend/config/activityCheckers.ts | 65 +++-- frontend/config/agents.ts | 61 +++-- frontend/config/chains.ts | 15 +- frontend/config/olasContracts.ts | 12 + frontend/config/stakingPrograms/base.ts | 75 ++++-- frontend/config/stakingPrograms/celo.ts | 14 +- frontend/config/stakingPrograms/gnosis.ts | 84 +++--- frontend/config/stakingPrograms/index.ts | 17 +- frontend/config/stakingPrograms/mode.ts | 54 ++-- frontend/config/stakingPrograms/optimism.ts | 101 +++++++ frontend/config/tokens.ts | 26 ++ frontend/constants/serviceTemplates.ts | 142 +++++++++- frontend/constants/urls.ts | 21 +- frontend/context/ElectronApiProvider.tsx | 4 +- .../StakingContractDetailsProvider.tsx | 1 - frontend/enums/Agent.ts | 1 + frontend/enums/Chain.ts | 8 +- frontend/enums/StakingProgram.ts | 78 ++++-- frontend/hooks/useFeatureFlag.ts | 11 + frontend/public/agent-optimus-icon.png | Bin 0 -> 47446 bytes frontend/public/setup-agent-optimus-1.png | Bin 0 -> 38724 bytes frontend/public/setup-agent-optimus-2.png | Bin 0 -> 32062 bytes frontend/public/setup-agent-optimus-3.png | Bin 0 -> 18210 bytes frontend/service/agents/Optimism.ts | 251 ++++++++++++++++++ frontend/types/Agent.ts | 16 +- frontend/types/Autonolas.ts | 2 + frontend/types/ElectronApi.ts | 1 + frontend/types/Util.ts | 2 + frontend/utils/middlewareHelpers.ts | 4 + frontend/utils/service.ts | 10 +- frontend/utils/setupMulticall.ts | 1 + templates/memeooorr.yaml | 79 ------ templates/optimus.yaml | 43 --- templates/trader.yaml | 60 ----- 50 files changed, 1464 insertions(+), 400 deletions(-) create mode 100644 frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx create mode 100644 frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate.ts rename frontend/components/SetupPage/SetupYourAgent/{ModiusAgentForm => shared}/labels.tsx (87%) create mode 100644 frontend/components/UpdateAgentPage/OptimusUpdateForm.tsx create mode 100644 frontend/config/stakingPrograms/optimism.ts create mode 100644 frontend/public/agent-optimus-icon.png create mode 100644 frontend/public/setup-agent-optimus-1.png create mode 100644 frontend/public/setup-agent-optimus-2.png create mode 100644 frontend/public/setup-agent-optimus-3.png create mode 100644 frontend/service/agents/Optimism.ts delete mode 100644 templates/memeooorr.yaml delete mode 100644 templates/optimus.yaml delete mode 100644 templates/trader.yaml diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index 1fcf8f7b9..f943aa482 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -1,3 +1,5 @@ +import { ValueOf } from '@/types/Util'; + export enum MiddlewareAction { STATUS = 0, BUILD = 1, @@ -5,17 +7,33 @@ export enum MiddlewareAction { STOP = 3, } +/** + * @note Use this enum to infer all the middleware chains existing in the system + * else use the SupportedMiddlewareChain enum for the chains that are supported by the agents and to be strictly typed. + * + * @warning The value doesn’t actually represent the real chain name; + * it reflects the open-autonomy internal name instead. + */ export enum MiddlewareChain { ETHEREUM = 'ethereum', GOERLI = 'goerli', GNOSIS = 'gnosis', SOLANA = 'solana', - OPTIMISM = 'optimism', + OPTIMISM = 'optimistic', // @note "optimistic" and not "optimism" BASE = 'base', MODE = 'mode', CELO = 'celo', } +const MIDDLEWARE_CHAINS = { + gnosis: MiddlewareChain.GNOSIS, + optimism: MiddlewareChain.OPTIMISM, + base: MiddlewareChain.BASE, + mode: MiddlewareChain.MODE, + celo: MiddlewareChain.CELO, +} as const; +export type SupportedMiddlewareChain = ValueOf; + export enum MiddlewareLedger { ETHEREUM = 0, SOLANA = 1, diff --git a/frontend/client/types.ts b/frontend/client/types.ts index b104e783e..88f2616bc 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -81,8 +81,8 @@ export type ServiceTemplate = { description: string; image: string; service_version: string; - home_chain: string; - configurations: { [key: string]: ConfigurationTemplate }; + home_chain: MiddlewareChain; + configurations: Partial>; env_variables: { [key: string]: EnvVariableAttributes }; deploy?: boolean; }; diff --git a/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx b/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx index d46ef9156..a7766621d 100644 --- a/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx +++ b/frontend/components/MainPage/sections/AlertSections/LowFunds/FundsToActivate.tsx @@ -28,6 +28,7 @@ const FUNDS_REQUIRED_FOR_BY_AGENT_TYPE: { [key in AgentType]: string } = { [AgentType.PredictTrader]: 'for trading', [AgentType.Memeooorr]: 'for agent operations', [AgentType.Modius]: 'for investment', + [AgentType.Optimus]: 'for investment', [AgentType.AgentsFunCelo]: 'for agent operations', } as const; @@ -81,7 +82,10 @@ export const FundsToActivate = ({ const getOlasText = useMemo(() => { const chainName = CHAIN_CONFIG[homeChainId].name; - if (homeChainId === EvmChainId.Mode) { + if ( + homeChainId === EvmChainId.Mode || + homeChainId === EvmChainId.Optimism + ) { return `Get OLAS + USDC on ${chainName}`; } return `Get OLAS on ${chainName}`; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index 27b92d3d3..792cd3ea8 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -5,7 +5,7 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus, ServiceTemplate } from '@/client'; import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; import { Pages } from '@/enums/Pages'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { STAKING_PROGRAM_IDS, StakingProgramId } from '@/enums/StakingProgram'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useModals } from '@/hooks/useModals'; import { usePageState } from '@/hooks/usePageState'; @@ -146,7 +146,7 @@ export const MigrateButton = ({ staking_program_id: stakingProgramIdToMigrateTo, use_mech_marketplace: stakingProgramIdToMigrateTo === - StakingProgramId.PearlBetaMechMarketplace, + STAKING_PROGRAM_IDS.PearlBetaMechMarketplace, }; return acc; }, @@ -164,7 +164,7 @@ export const MigrateButton = ({ deploy: true, useMechMarketplace: stakingProgramIdToMigrateTo === - StakingProgramId.PearlBetaMechMarketplace, + STAKING_PROGRAM_IDS.PearlBetaMechMarketplace, }; await ServicesService.createService(serviceConfigParams); diff --git a/frontend/components/SetupPage/AgentIntroduction/AgentIntroduction.tsx b/frontend/components/SetupPage/AgentIntroduction/AgentIntroduction.tsx index 52ebad2b6..38cb75855 100644 --- a/frontend/components/SetupPage/AgentIntroduction/AgentIntroduction.tsx +++ b/frontend/components/SetupPage/AgentIntroduction/AgentIntroduction.tsx @@ -9,6 +9,7 @@ import { useSharedContext } from '@/hooks/useSharedContext'; import { AGENTS_FUND_ONBOARDING_STEPS, MODIUS_ONBOARDING_STEPS, + OPTIMUS_ONBOARDING_STEPS, PREDICTION_ONBOARDING_STEPS, } from './constants'; import { IntroductionStep, OnboardingStep } from './IntroductionStep'; @@ -71,6 +72,7 @@ export const AgentIntroduction = () => { if (selectedAgentType === 'trader') return PREDICTION_ONBOARDING_STEPS; if (selectedAgentType === 'memeooorr') return AGENTS_FUND_ONBOARDING_STEPS; if (selectedAgentType === 'modius') return MODIUS_ONBOARDING_STEPS; + if (selectedAgentType === 'optimus') return OPTIMUS_ONBOARDING_STEPS; throw new Error('Invalid agent type'); }, [selectedAgentType]); diff --git a/frontend/components/SetupPage/AgentIntroduction/constants.ts b/frontend/components/SetupPage/AgentIntroduction/constants.ts index 44034ccf2..fdcd7ea42 100644 --- a/frontend/components/SetupPage/AgentIntroduction/constants.ts +++ b/frontend/components/SetupPage/AgentIntroduction/constants.ts @@ -55,3 +55,21 @@ export const MODIUS_ONBOARDING_STEPS: OnboardingStep[] = [ imgSrc: 'setup-agent-modius-3', }, ] as const; + +export const OPTIMUS_ONBOARDING_STEPS: OnboardingStep[] = [ + { + title: 'Your AI portfolio manager', + desc: 'Optimus collects real-time market data from CoinGecko and autonomously manages your investments using Balancer, Sturdy and Uniswap — delivering hands-free portfolio growth. Requires ETH and USDC on Optimism as initial investments.', + imgSrc: 'setup-agent-optimus-1', + }, + { + title: 'Choose the best strategy', + desc: 'Optimus learns autonomously, adapts to changing market conditions, and selects the best next strategy to invest on your behalf.', + imgSrc: 'setup-agent-optimus-2', + }, + // { + // title: 'Take action', + // desc: 'Based on its analysis and real-time market data, your Optimus agent decides when its more convenient to buy, sell, or hold specific assets.', + // imgSrc: 'setup-agent-optimus-3', + // }, +] as const; diff --git a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx b/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx index 70da814b3..18eedc357 100644 --- a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx +++ b/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx @@ -9,21 +9,21 @@ import { useSetup } from '@/hooks/useSetup'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { - modiusAgentFieldProps, + agentFieldProps, requiredRules, validateApiKey, validateMessages, validateSlug, } from '../shared/formUtils'; import { InvalidGeminiApiCredentials } from '../shared/InvalidGeminiApiCredentials'; -import { onDummyServiceCreation } from '../shared/utils'; import { CoinGeckoApiKeyLabel, ModiusGeminiApiKeyLabel, TenderlyAccessTokenLabel, TenderlyAccountSlugLabel, TenderlyProjectSlugLabel, -} from './labels'; +} from '../shared/labels'; +import { onDummyServiceCreation } from '../shared/utils'; import { ModiusFieldValues, useModiusFormValidate, @@ -150,7 +150,7 @@ export const ModiusAgentForm = ({ serviceTemplate }: ModiusAgentFormProps) => { } - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[...requiredRules, { validator: validateApiKey }]} > @@ -159,7 +159,7 @@ export const ModiusAgentForm = ({ serviceTemplate }: ModiusAgentFormProps) => { } - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[...requiredRules, { validator: validateSlug }]} > @@ -168,7 +168,7 @@ export const ModiusAgentForm = ({ serviceTemplate }: ModiusAgentFormProps) => { } - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[...requiredRules, { validator: validateSlug }]} > @@ -177,7 +177,7 @@ export const ModiusAgentForm = ({ serviceTemplate }: ModiusAgentFormProps) => { } - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[...requiredRules, { validator: validateApiKey }]} > @@ -186,7 +186,7 @@ export const ModiusAgentForm = ({ serviceTemplate }: ModiusAgentFormProps) => { } - {...modiusAgentFieldProps} + {...agentFieldProps} > diff --git a/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx new file mode 100644 index 000000000..70035aaf2 --- /dev/null +++ b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx @@ -0,0 +1,214 @@ +import { Button, Divider, Form, Input, message, Typography } from 'antd'; +import React, { useCallback, useState } from 'react'; +import { useUnmount } from 'usehooks-ts'; + +import { ServiceTemplate } from '@/client'; +import { COINGECKO_URL, TENDERLY_URL } from '@/constants/urls'; +import { SetupScreen } from '@/enums/SetupScreen'; +import { useSetup } from '@/hooks/useSetup'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; + +import { + agentFieldProps, + requiredRules, + validateApiKey, + validateMessages, + validateSlug, +} from '../shared/formUtils'; +import { InvalidGeminiApiCredentials } from '../shared/InvalidGeminiApiCredentials'; +import { + CoinGeckoApiKeyLabel, + OptimusGeminiApiKeyLabel, + TenderlyAccessTokenLabel, + TenderlyAccountSlugLabel, + TenderlyProjectSlugLabel, +} from '../shared/labels'; +import { onDummyServiceCreation } from '../shared/utils'; +import { + OptimusFieldValues, + useOptimusFormValidate, +} from './useOptimusFormValidate'; + +const { Text } = Typography; + +const SetupHeader = () => ( + + Set up your agent with access to a{' '} + + Tenderly + {' '} + project for simulating bridge and swap routes, and swap routes and provide a{' '} + + CoinGecko API key + {' '} + as a price source. + +); + +type OptimusAgentFormProps = { serviceTemplate: ServiceTemplate }; + +export const OptimusAgentForm = ({ + serviceTemplate, +}: OptimusAgentFormProps) => { + const { goto } = useSetup(); + const { defaultStakingProgramId } = useStakingProgram(); + + const [form] = Form.useForm(); + const [isSubmitting, setIsSubmitting] = useState(false); + const { + geminiApiKeyValidationStatus, + submitButtonText, + updateSubmitButtonText, + validateForm, + } = useOptimusFormValidate(); + + const onFinish = useCallback( + async (values: OptimusFieldValues) => { + if (!defaultStakingProgramId) return; + + try { + setIsSubmitting(true); + + // wait for agent setup to complete + updateSubmitButtonText('Setting up agent...'); + + const isFormValid = await validateForm(values); + if (!isFormValid) return; + + const overriddenServiceConfig: ServiceTemplate = { + ...serviceTemplate, + env_variables: { + ...serviceTemplate.env_variables, + TENDERLY_ACCESS_KEY: { + ...serviceTemplate.env_variables.TENDERLY_ACCESS_KEY, + value: values.tenderlyAccessToken, + }, + TENDERLY_ACCOUNT_SLUG: { + ...serviceTemplate.env_variables.TENDERLY_ACCOUNT_SLUG, + value: values.tenderlyAccountSlug, + }, + TENDERLY_PROJECT_SLUG: { + ...serviceTemplate.env_variables.TENDERLY_PROJECT_SLUG, + value: values.tenderlyProjectSlug, + }, + COINGECKO_API_KEY: { + ...serviceTemplate.env_variables.COINGECKO_API_KEY, + value: values.coinGeckoApiKey, + }, + GENAI_API_KEY: { + ...serviceTemplate.env_variables.GENAI_API_KEY, + value: values.geminiApiKey || '', + }, + }, + }; + + await onDummyServiceCreation( + defaultStakingProgramId, + overriddenServiceConfig, + ); + + message.success('Agent setup complete'); + + // move to next page + goto(SetupScreen.SetupEoaFunding); + } catch (error) { + message.error('Something went wrong. Please try again.'); + console.error(error); + } finally { + setIsSubmitting(false); + updateSubmitButtonText('Continue'); + } + }, + [ + defaultStakingProgramId, + serviceTemplate, + validateForm, + updateSubmitButtonText, + goto, + ], + ); + + // Clean up + useUnmount(async () => { + setIsSubmitting(false); + updateSubmitButtonText('Continue'); + }); + + const canSubmitForm = isSubmitting || !defaultStakingProgramId; + + return ( + <> + + + + + form={form} + name="setup-your-agent" + layout="vertical" + onFinish={onFinish} + validateMessages={validateMessages} + disabled={canSubmitForm} + > + } + {...agentFieldProps} + rules={[...requiredRules, { validator: validateApiKey }]} + > + + + + } + {...agentFieldProps} + rules={[...requiredRules, { validator: validateSlug }]} + > + + + + } + {...agentFieldProps} + rules={[...requiredRules, { validator: validateSlug }]} + > + + + + } + {...agentFieldProps} + rules={[...requiredRules, { validator: validateApiKey }]} + > + + + + } + {...agentFieldProps} + > + + + {geminiApiKeyValidationStatus === 'invalid' && ( + + )} + + + + + + + ); +}; diff --git a/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate.ts b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate.ts new file mode 100644 index 000000000..607882937 --- /dev/null +++ b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate.ts @@ -0,0 +1,58 @@ +import { useCallback, useState } from 'react'; + +import { validateGeminiApiKey, ValidationStatus } from '../shared/validations'; + +export type OptimusFieldValues = { + tenderlyAccessToken: string; + tenderlyAccountSlug: string; + tenderlyProjectSlug: string; + coinGeckoApiKey: string; + geminiApiKey?: string; +}; + +export const useOptimusFormValidate = ( + defaultSubmitButtonText = 'Continue', +) => { + const [isValidating, setIsValidating] = useState(false); + const [submitButtonText, setSubmitButtonText] = useState( + defaultSubmitButtonText, + ); + const [geminiApiKeyValidationStatus, setGeminiApiKeyValidationStatus] = + useState('unknown'); + + const handleValidate = useCallback(async (values: OptimusFieldValues) => { + setIsValidating(true); + + setGeminiApiKeyValidationStatus('unknown'); + setSubmitButtonText('Validating...'); + + try { + // gemini api key is optional, so we only validate if it's provided + if (values.geminiApiKey) { + const isGeminiApiValid = await validateGeminiApiKey( + values.geminiApiKey, + ); + setGeminiApiKeyValidationStatus(isGeminiApiValid ? 'valid' : 'invalid'); + if (!isGeminiApiValid) return; + } + + return true; + } catch (error) { + console.error('Error validating optimus form:', error); + } finally { + setIsValidating(false); + } + }, []); + + const updateSubmitButtonText = useCallback((value: string) => { + setSubmitButtonText(value); + }, []); + + return { + isValidating, + geminiApiKeyValidationStatus, + submitButtonText, + updateSubmitButtonText, + validateForm: handleValidate, + }; +}; diff --git a/frontend/components/SetupPage/SetupYourAgent/SetupYourAgent.tsx b/frontend/components/SetupPage/SetupYourAgent/SetupYourAgent.tsx index 79fd2f2fa..60c7f9da8 100644 --- a/frontend/components/SetupPage/SetupYourAgent/SetupYourAgent.tsx +++ b/frontend/components/SetupPage/SetupYourAgent/SetupYourAgent.tsx @@ -12,6 +12,7 @@ import { LOCAL_FORM_THEME } from '@/theme'; import { SetupCreateHeader } from '../Create/SetupCreateHeader'; import { MemeooorrAgentForm } from './MemeooorrAgentForm/MemeooorrAgentForm'; import { ModiusAgentForm } from './ModiusAgentForm/ModiusAgentForm'; +import { OptimusAgentForm } from './OptimusAgentForm/OptimusAgentForm'; const { Title, Text } = Typography; @@ -41,10 +42,12 @@ export const SetupYourAgent = () => { {selectedAgentType === AgentType.Memeooorr && ( )} - {selectedAgentType === AgentType.Modius && ( )} + {selectedAgentType === AgentType.Optimus && ( + + )} ); diff --git a/frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts b/frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts index 15ff79241..8405763ef 100644 --- a/frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts +++ b/frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts @@ -7,7 +7,7 @@ export const commonFieldProps: FormItemProps = { hasFeedback: true, } as const; -export const modiusAgentFieldProps: FormItemProps = { +export const agentFieldProps: FormItemProps = { ...commonFieldProps, validateFirst: true, normalize: (value: string) => value.trim(), diff --git a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/labels.tsx b/frontend/components/SetupPage/SetupYourAgent/shared/labels.tsx similarity index 87% rename from frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/labels.tsx rename to frontend/components/SetupPage/SetupYourAgent/shared/labels.tsx index e5ed2845b..629067726 100644 --- a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/labels.tsx +++ b/frontend/components/SetupPage/SetupYourAgent/shared/labels.tsx @@ -25,7 +25,7 @@ export const TenderlyAccessTokenLabel = () => ( To locate your personal access token: -
    +
    1. Connect to{' '} @@ -136,3 +136,22 @@ export const ModiusGeminiApiKeyLabel = () => ( ); + +export const OptimusGeminiApiKeyLabel = () => ( + + Gemini API key + + + The Gemini API key allows you to chat with your agent and update its + goals through Optimus’ profile. You can generate one for free on{' '} + + Google AI Studio + + . + + + + (Optional) + + +); diff --git a/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx b/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx index 5040b3f88..10844bf78 100644 --- a/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx +++ b/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx @@ -7,24 +7,24 @@ import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; import { Nullable } from '@/types/Util'; -import { - CoinGeckoApiKeyLabel, - ModiusGeminiApiKeyLabel, - TenderlyAccessTokenLabel, - TenderlyAccountSlugLabel, - TenderlyProjectSlugLabel, -} from '../SetupPage/SetupYourAgent/ModiusAgentForm/labels'; import { useModiusFormValidate } from '../SetupPage/SetupYourAgent/ModiusAgentForm/useModiusFormValidate'; // TODO: move the following hook/components to a shared place // once Modius work is merged import { - modiusAgentFieldProps, + agentFieldProps, requiredRules, validateApiKey, validateMessages, validateSlug, } from '../SetupPage/SetupYourAgent/shared/formUtils'; import { InvalidGeminiApiCredentials } from '../SetupPage/SetupYourAgent/shared/InvalidGeminiApiCredentials'; +import { + CoinGeckoApiKeyLabel, + ModiusGeminiApiKeyLabel, + TenderlyAccessTokenLabel, + TenderlyAccountSlugLabel, + TenderlyProjectSlugLabel, +} from '../SetupPage/SetupYourAgent/shared/labels'; import { CardLayout } from './CardLayout'; import { UpdateAgentContext } from './context/UpdateAgentProvider'; @@ -93,7 +93,7 @@ const ModiusUpdateForm = ({ initialFormValues }: ModiusUpdateFormProps) => { } name={['env_variables', 'TENDERLY_ACCESS_KEY']} - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[...requiredRules, { validator: validateApiKey }]} > @@ -102,7 +102,7 @@ const ModiusUpdateForm = ({ initialFormValues }: ModiusUpdateFormProps) => { } name={['env_variables', 'TENDERLY_ACCOUNT_SLUG']} - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[...requiredRules, { validator: validateSlug }]} > @@ -111,7 +111,7 @@ const ModiusUpdateForm = ({ initialFormValues }: ModiusUpdateFormProps) => { } name={['env_variables', 'TENDERLY_PROJECT_SLUG']} - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[...requiredRules, { validator: validateSlug }]} > @@ -120,7 +120,7 @@ const ModiusUpdateForm = ({ initialFormValues }: ModiusUpdateFormProps) => { } name={['env_variables', 'COINGECKO_API_KEY']} - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[...requiredRules, { validator: validateApiKey }]} > @@ -129,7 +129,7 @@ const ModiusUpdateForm = ({ initialFormValues }: ModiusUpdateFormProps) => { } name={['env_variables', 'GENAI_API_KEY']} - {...modiusAgentFieldProps} + {...agentFieldProps} rules={[{ validator: validateApiKey }]} > diff --git a/frontend/components/UpdateAgentPage/OptimusUpdateForm.tsx b/frontend/components/UpdateAgentPage/OptimusUpdateForm.tsx new file mode 100644 index 000000000..6c4528b16 --- /dev/null +++ b/frontend/components/UpdateAgentPage/OptimusUpdateForm.tsx @@ -0,0 +1,202 @@ +import { Button, Form, Input } from 'antd'; +import { get, isEqual, isUndefined, omitBy } from 'lodash'; +import { useCallback, useContext, useMemo } from 'react'; + +import { Pages } from '@/enums/Pages'; +import { usePageState } from '@/hooks/usePageState'; +import { useServices } from '@/hooks/useServices'; +import { Nullable } from '@/types/Util'; + +import { useOptimusFormValidate } from '../SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate'; +import { + agentFieldProps, + requiredRules, + validateApiKey, + validateMessages, + validateSlug, +} from '../SetupPage/SetupYourAgent/shared/formUtils'; +import { InvalidGeminiApiCredentials } from '../SetupPage/SetupYourAgent/shared/InvalidGeminiApiCredentials'; +import { + CoinGeckoApiKeyLabel, + OptimusGeminiApiKeyLabel, + TenderlyAccessTokenLabel, + TenderlyAccountSlugLabel, + TenderlyProjectSlugLabel, +} from '../SetupPage/SetupYourAgent/shared/labels'; +import { CardLayout } from './CardLayout'; +import { UpdateAgentContext } from './context/UpdateAgentProvider'; + +type OptimusFormValues = { + env_variables: { + TENDERLY_ACCESS_KEY: string; + TENDERLY_ACCOUNT_SLUG: string; + TENDERLY_PROJECT_SLUG: string; + COINGECKO_API_KEY: string; + GENAI_API_KEY: string; + }; +}; + +type OptimusUpdateFormProps = { + initialFormValues: Nullable; +}; + +const OptimusUpdateForm = ({ initialFormValues }: OptimusUpdateFormProps) => { + const { + isEditing, + form, + confirmUpdateModal: confirmModal, + } = useContext(UpdateAgentContext); + + const { + geminiApiKeyValidationStatus, + submitButtonText, + updateSubmitButtonText, + validateForm, + } = useOptimusFormValidate('Save Changes'); + + const handleFinish = useCallback( + async (values: OptimusFormValues) => { + try { + const envVariables = values.env_variables; + const userInputs = { + tenderlyAccessToken: envVariables.TENDERLY_ACCESS_KEY, + tenderlyAccountSlug: envVariables.TENDERLY_ACCOUNT_SLUG, + tenderlyProjectSlug: envVariables.TENDERLY_PROJECT_SLUG, + coinGeckoApiKey: envVariables.COINGECKO_API_KEY, + geminiApiKey: envVariables.GENAI_API_KEY, + }; + const isFormValid = await validateForm(userInputs); + if (!isFormValid) return; + + updateSubmitButtonText('Updating agent...'); + confirmModal.openModal(); + } catch (error) { + console.error('Error validating form:', error); + } finally { + updateSubmitButtonText('Save Changes'); + } + }, + [validateForm, confirmModal, updateSubmitButtonText], + ); + + return ( + + form={form} + layout="vertical" + disabled={!isEditing} + onFinish={handleFinish} + validateMessages={validateMessages} + initialValues={{ ...initialFormValues }} + > + } + name={['env_variables', 'TENDERLY_ACCESS_KEY']} + {...agentFieldProps} + rules={[...requiredRules, { validator: validateApiKey }]} + > + + + + } + name={['env_variables', 'TENDERLY_ACCOUNT_SLUG']} + {...agentFieldProps} + rules={[...requiredRules, { validator: validateSlug }]} + > + + + + } + name={['env_variables', 'TENDERLY_PROJECT_SLUG']} + {...agentFieldProps} + rules={[...requiredRules, { validator: validateSlug }]} + > + + + + } + name={['env_variables', 'COINGECKO_API_KEY']} + {...agentFieldProps} + rules={[...requiredRules, { validator: validateApiKey }]} + > + + + + } + name={['env_variables', 'GENAI_API_KEY']} + {...agentFieldProps} + rules={[{ validator: validateApiKey }]} + > + + + {geminiApiKeyValidationStatus === 'invalid' && ( + + )} + + + + ); +}; + +/** + * Form for updating Optimus agent. + */ +export const OptimusUpdatePage = () => { + const { goto } = usePageState(); + const { selectedService } = useServices(); + const { unsavedModal, form } = useContext(UpdateAgentContext); + + const initialValues = useMemo>(() => { + if (!selectedService?.env_variables) return null; + + const envEntries = Object.entries(selectedService.env_variables); + + return envEntries.reduce( + (acc, [key, { value }]) => { + if (key === 'TENDERLY_ACCESS_KEY') { + acc.env_variables.TENDERLY_ACCESS_KEY = value; + } else if (key === 'TENDERLY_ACCOUNT_SLUG') { + acc.env_variables.TENDERLY_ACCOUNT_SLUG = value; + } else if (key === 'TENDERLY_PROJECT_SLUG') { + acc.env_variables.TENDERLY_PROJECT_SLUG = value; + } else if (key === 'COINGECKO_API_KEY') { + acc.env_variables.COINGECKO_API_KEY = value; + } else if (key === 'GENAI_API_KEY') { + acc.env_variables.GENAI_API_KEY = value; + } + + return acc; + }, + { env_variables: {} } as OptimusFormValues, + ); + }, [selectedService?.env_variables]); + + const handleBackClick = useCallback(() => { + // Check if there are unsaved changes and omit empty fields + const unsavedFields = omitBy( + get(form?.getFieldsValue(), 'env_variables'), + (value) => isUndefined(value), + ); + const previousValues = initialValues?.env_variables; + + const hasUnsavedChanges = !isEqual(unsavedFields, previousValues); + if (hasUnsavedChanges) { + unsavedModal.openModal(); + } else { + goto(Pages.Main); + } + }, [initialValues, form, unsavedModal, goto]); + + return ( + + + + ); +}; diff --git a/frontend/components/UpdateAgentPage/index.tsx b/frontend/components/UpdateAgentPage/index.tsx index 26a21d549..6ee8765d9 100644 --- a/frontend/components/UpdateAgentPage/index.tsx +++ b/frontend/components/UpdateAgentPage/index.tsx @@ -7,6 +7,7 @@ import { LOCAL_FORM_THEME } from '@/theme'; import { UpdateAgentProvider } from './context/UpdateAgentProvider'; import { MemeooorrUpdatePage } from './MemeooorrUpdatePage'; import { ModiusUpdatePage } from './ModiusUpdateForm'; +import { OptimusUpdatePage } from './OptimusUpdateForm'; export const UpdateAgentPage = () => { const { selectedAgentType } = useServices(); @@ -15,6 +16,7 @@ export const UpdateAgentPage = () => { {selectedAgentType === AgentType.Memeooorr && } {selectedAgentType === AgentType.Modius && } + {selectedAgentType === AgentType.Optimus && } ); diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index aa2fb556e..45ccfb9f8 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -19,6 +19,7 @@ import { useServices } from '@/hooks/useServices'; import { Address } from '@/types/Address'; import { WalletBalance } from '@/types/Balance'; import { balanceFormat } from '@/utils/numberFormatters'; +import { isValidServiceId } from '@/utils/service'; import { truncateAddress } from '@/utils/truncate'; import { AddressLink } from '../AddressLink'; @@ -281,7 +282,7 @@ const YourAgentWalletBreakdown = () => { )} - {!isNil(serviceNftTokenId) && ( + {serviceNftTokenId && isValidServiceId(serviceNftTokenId) && ( )} diff --git a/frontend/config/activityCheckers.ts b/frontend/config/activityCheckers.ts index 5d92bc25f..0daf9a786 100644 --- a/frontend/config/activityCheckers.ts +++ b/frontend/config/activityCheckers.ts @@ -4,7 +4,10 @@ import { MECH_ACTIVITY_CHECKER_ABI } from '@/abis/mechActivityChecker'; import { MEME_ACTIVITY_CHECKER_ABI } from '@/abis/memeActivityChecker'; import { REQUESTER_ACTIVITY_CHECKER_ABI } from '@/abis/requesterActivityChecker'; import { STAKING_ACTIVITY_CHECKER_ABI } from '@/abis/stakingActivityChecker'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { + OptimismStakingProgramId, + STAKING_PROGRAM_IDS, +} from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; export const getMechActivityCheckerContract = ( @@ -35,28 +38,28 @@ export const GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS: Record< string, MulticallContract > = { - [StakingProgramId.PearlAlpha]: getMechActivityCheckerContract( + [STAKING_PROGRAM_IDS.PearlAlpha]: getMechActivityCheckerContract( '0x155547857680A6D51bebC5603397488988DEb1c8', ), - [StakingProgramId.PearlBeta]: getMechActivityCheckerContract( + [STAKING_PROGRAM_IDS.PearlBeta]: getMechActivityCheckerContract( '0x155547857680A6D51bebC5603397488988DEb1c8', ), - [StakingProgramId.PearlBeta2]: getMechActivityCheckerContract( + [STAKING_PROGRAM_IDS.PearlBeta2]: getMechActivityCheckerContract( '0x155547857680A6D51bebC5603397488988DEb1c8', ), - [StakingProgramId.PearlBeta3]: getMechActivityCheckerContract( + [STAKING_PROGRAM_IDS.PearlBeta3]: getMechActivityCheckerContract( '0x155547857680A6D51bebC5603397488988DEb1c8', ), - [StakingProgramId.PearlBeta4]: getMechActivityCheckerContract( + [STAKING_PROGRAM_IDS.PearlBeta4]: getMechActivityCheckerContract( '0x155547857680A6D51bebC5603397488988DEb1c8', ), - [StakingProgramId.PearlBeta5]: getMechActivityCheckerContract( + [STAKING_PROGRAM_IDS.PearlBeta5]: getMechActivityCheckerContract( '0x155547857680A6D51bebC5603397488988DEb1c8', ), - [StakingProgramId.PearlBeta6]: getRequesterActivityCheckerContract( + [STAKING_PROGRAM_IDS.PearlBeta6]: getRequesterActivityCheckerContract( '0xfE1D36820546cE5F3A58405950dC2F5ccDf7975C', ), - [StakingProgramId.PearlBetaMechMarketplace]: + [STAKING_PROGRAM_IDS.PearlBetaMechMarketplace]: getRequesterActivityCheckerContract( '0x7Ec96996Cd146B91779f01419db42E67463817a0', ), @@ -66,25 +69,25 @@ export const BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS: Record< string, MulticallContract > = { - [StakingProgramId.MemeBaseAlpha2]: getMemeActivityCheckerContract( + [STAKING_PROGRAM_IDS.MemeBaseAlpha2]: getMemeActivityCheckerContract( '0x026AB1c5ea14E61f67d245685D9561c0c2Cb39Ba', ), - [StakingProgramId.MemeBaseBeta]: getMemeActivityCheckerContract( + [STAKING_PROGRAM_IDS.MemeBaseBeta]: getMemeActivityCheckerContract( '0x008F52AF7009e262967caa7Cb79468F92AFEADF9', ), - [StakingProgramId.MemeBaseBeta2]: getMemeActivityCheckerContract( + [STAKING_PROGRAM_IDS.MemeBaseBeta2]: getMemeActivityCheckerContract( '0x026AB1c5ea14E61f67d245685D9561c0c2Cb39Ba', ), - [StakingProgramId.MemeBaseBeta3]: getMemeActivityCheckerContract( + [STAKING_PROGRAM_IDS.MemeBaseBeta3]: getMemeActivityCheckerContract( '0x026AB1c5ea14E61f67d245685D9561c0c2Cb39Ba', ), - [StakingProgramId.AgentsFun1]: getRequesterActivityCheckerContract( + [STAKING_PROGRAM_IDS.AgentsFun1]: getRequesterActivityCheckerContract( '0x87C9922A099467E5A80367553e7003349FE50106', ), - [StakingProgramId.AgentsFun2]: getRequesterActivityCheckerContract( + [STAKING_PROGRAM_IDS.AgentsFun2]: getRequesterActivityCheckerContract( '0x4bEb05F76f4563DE7BCB6276915C3E1F71184D8f', ), - [StakingProgramId.AgentsFun3]: getRequesterActivityCheckerContract( + [STAKING_PROGRAM_IDS.AgentsFun3]: getRequesterActivityCheckerContract( '0xF0814A105c1b684922Fce8C3b80d7B6Ff1e399F9', ), } as const; @@ -93,28 +96,46 @@ export const MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS: Record< string, MulticallContract > = { - [StakingProgramId.ModiusAlpha]: getStakingActivityCheckerContract( + [STAKING_PROGRAM_IDS.ModiusAlpha]: getStakingActivityCheckerContract( '0x07bc3C23DbebEfBF866Ca7dD9fAA3b7356116164', ), - [StakingProgramId.OptimusAlpha]: getStakingActivityCheckerContract( + [STAKING_PROGRAM_IDS.OptimusAlpha]: getStakingActivityCheckerContract( '0x07bc3C23DbebEfBF866Ca7dD9fAA3b7356116164', ), - [StakingProgramId.ModiusAlpha2]: getStakingActivityCheckerContract( + [STAKING_PROGRAM_IDS.ModiusAlpha2]: getStakingActivityCheckerContract( '0x07bc3C23DbebEfBF866Ca7dD9fAA3b7356116164', ), - [StakingProgramId.ModiusAlpha3]: getStakingActivityCheckerContract( + [STAKING_PROGRAM_IDS.ModiusAlpha3]: getStakingActivityCheckerContract( '0x07bc3C23DbebEfBF866Ca7dD9fAA3b7356116164', ), - [StakingProgramId.ModiusAlpha4]: getStakingActivityCheckerContract( + [STAKING_PROGRAM_IDS.ModiusAlpha4]: getStakingActivityCheckerContract( '0x07bc3C23DbebEfBF866Ca7dD9fAA3b7356116164', ), } as const; +export const OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS: Record< + OptimismStakingProgramId, + MulticallContract +> = { + [STAKING_PROGRAM_IDS.OptimusAlpha1]: getStakingActivityCheckerContract( + '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', + ), + // [STAKING_PROGRAM_IDS.OptimusAlpha2]: getStakingActivityCheckerContract( + // '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', + // ), + // [STAKING_PROGRAM_IDS.OptimusAlpha3]: getStakingActivityCheckerContract( + // '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', + // ), + // [STAKING_PROGRAM_IDS.OptimusAlpha4]: getStakingActivityCheckerContract( + // '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', + // ), +} as const; + export const CELO_STAKING_PROGRAMS_ACTIVITY_CHECKERS: Record< string, MulticallContract > = { - [StakingProgramId.MemeCeloAlpha2]: getMemeActivityCheckerContract( + [STAKING_PROGRAM_IDS.MemeCeloAlpha2]: getMemeActivityCheckerContract( '0x3FD8C757dE190bcc82cF69Df3Cd9Ab15bCec1426', ), } as const; diff --git a/frontend/config/agents.ts b/frontend/config/agents.ts index 74638fee9..e66bdb742 100644 --- a/frontend/config/agents.ts +++ b/frontend/config/agents.ts @@ -1,24 +1,41 @@ import { formatUnits } from 'ethers/lib/utils'; import { MiddlewareChain } from '@/client'; -import { MODIUS_SERVICE_TEMPLATE } from '@/constants/serviceTemplates'; +import { + MODIUS_SERVICE_TEMPLATE, + OPTIMUS_SERVICE_TEMPLATE, +} from '@/constants/serviceTemplates'; import { AgentType } from '@/enums/Agent'; import { EvmChainId } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; import { AgentsFunBaseService } from '@/service/agents/AgentsFunBase'; import { ModiusService } from '@/service/agents/Modius'; +import { OptimismService } from '@/service/agents/Optimism'; import { PredictTraderService } from '@/service/agents/PredictTrader'; import { AgentConfig } from '@/types/Agent'; -import { MODE_TOKEN_CONFIG } from './tokens'; +import { MODE_TOKEN_CONFIG, OPTIMISM_TOKEN_CONFIG } from './tokens'; -const modiusFundRequirements = - MODIUS_SERVICE_TEMPLATE.configurations[MiddlewareChain.MODE] - .fund_requirements; -const modiusUsdcConfig = - modiusFundRequirements?.[ - MODE_TOKEN_CONFIG[TokenSymbol.USDC].address as string - ]; +const getModiusUsdcConfig = () => { + const modiusFundRequirements = + MODIUS_SERVICE_TEMPLATE.configurations[MiddlewareChain.MODE] + ?.fund_requirements; + const modiusUsdcConfig = MODE_TOKEN_CONFIG[TokenSymbol.USDC]; + const usdcSafeRequirement = + modiusFundRequirements?.[modiusUsdcConfig.address as string]?.safe || 0; + return Number(formatUnits(usdcSafeRequirement, modiusUsdcConfig.decimals)); +}; + +const getOptimusUsdcConfig = () => { + const optimusFundRequirements = + OPTIMUS_SERVICE_TEMPLATE.configurations[MiddlewareChain.OPTIMISM] + ?.fund_requirements; + const optimusUsdcConfig = OPTIMISM_TOKEN_CONFIG[TokenSymbol.USDC]; + const usdcSafeRequirement = + optimusFundRequirements?.[optimusUsdcConfig.address as string]?.safe || 0; + + return Number(formatUnits(usdcSafeRequirement, optimusUsdcConfig.decimals)); +}; export const AGENT_CONFIG: { [key in AgentType]: AgentConfig; @@ -58,14 +75,7 @@ export const AGENT_CONFIG: { middlewareHomeChainId: MiddlewareChain.MODE, requiresAgentSafesOn: [EvmChainId.Mode], additionalRequirements: { - [EvmChainId.Mode]: { - [TokenSymbol.USDC]: Number( - formatUnits( - modiusUsdcConfig?.safe || 0, - MODE_TOKEN_CONFIG[TokenSymbol.USDC].decimals, - ), - ), - }, + [EvmChainId.Mode]: { [TokenSymbol.USDC]: getModiusUsdcConfig() }, }, requiresMasterSafesOn: [EvmChainId.Mode], serviceApi: ModiusService, @@ -73,6 +83,23 @@ export const AGENT_CONFIG: { description: 'Invests crypto assets on your behalf and grows your portfolio on Mode network.', }, + [AgentType.Optimus]: { + isAgentEnabled: true, + isComingSoon: false, + requiresSetup: true, + name: 'Optimus agent', + evmHomeChainId: EvmChainId.Optimism, + middlewareHomeChainId: MiddlewareChain.OPTIMISM, + requiresAgentSafesOn: [EvmChainId.Optimism], + additionalRequirements: { + [EvmChainId.Optimism]: { [TokenSymbol.USDC]: getOptimusUsdcConfig() }, + }, + requiresMasterSafesOn: [EvmChainId.Optimism], + serviceApi: OptimismService, + displayName: 'Optimus agent', + description: + 'Invests crypto assets on your behalf and grows your portfolio on Optimus network.', + }, // TODO: celo (check each key) [AgentType.AgentsFunCelo]: { isAgentEnabled: false, diff --git a/frontend/config/chains.ts b/frontend/config/chains.ts index fb853ebfa..22191824c 100644 --- a/frontend/config/chains.ts +++ b/frontend/config/chains.ts @@ -18,8 +18,9 @@ export type ChainConfig = { rpc: HttpUrl; // TODO: the values are hardcoded, should be fetched from the backend /** - * Least amount of native token required to create a Safe - * @example for gnosis chain, 1.5 XDAI is required to create a Safe + * Least amount of native token required to create a Safe. + * @example for gnosis chain, 1.5 XDAI is required to create a Safe. + * For new chains, ask middleware team for the value. */ safeCreationThreshold: number; }; @@ -61,6 +62,15 @@ export const CELO_CHAIN_CONFIG: ChainConfig = { safeCreationThreshold: 0.005, } as const; +export const OPTIMISM_CHAIN_CONFIG: ChainConfig = { + evmChainId: EvmChainId.Optimism, + name: 'Optimism', + nativeToken: TOKEN_CONFIG[EvmChainId.Optimism][TokenSymbol.ETH], + middlewareChain: MiddlewareChainId.OPTIMISM, + rpc: process.env.OPTIMISM_RPC as HttpUrl, + safeCreationThreshold: 0.005, +} as const; + export const CHAIN_CONFIG: { [evmChainId in EvmChainId]: ChainConfig; } = { @@ -68,4 +78,5 @@ export const CHAIN_CONFIG: { [EvmChainId.Gnosis]: GNOSIS_CHAIN_CONFIG, [EvmChainId.Mode]: MODE_CHAIN_CONFIG, [EvmChainId.Celo]: CELO_CHAIN_CONFIG, + [EvmChainId.Optimism]: OPTIMISM_CHAIN_CONFIG, } as const; diff --git a/frontend/config/olasContracts.ts b/frontend/config/olasContracts.ts index 12303f635..bf398b250 100644 --- a/frontend/config/olasContracts.ts +++ b/frontend/config/olasContracts.ts @@ -42,6 +42,17 @@ const MODE_OLAS_CONTRACTS: ContractsByType = { ), }; +const OPTIMISM_OLAS_CONTRACTS: ContractsByType = { + [ContractType.ServiceRegistryL2]: new MulticallContract( + '0x3d77596beb0f130a4415df3D2D8232B3d3D31e44', + SERVICE_REGISTRY_L2_ABI, + ), + [ContractType.ServiceRegistryTokenUtility]: new MulticallContract( + '0xBb7e1D6Cb6F243D6bdE81CE92a9f2aFF7Fbe7eac', + SERVICE_REGISTRY_TOKEN_UTILITY_ABI, + ), +}; + const CELO_OLAS_CONTRACTS: ContractsByType = { [ContractType.ServiceRegistryL2]: new MulticallContract( '0xE3607b00E75f6405248323A9417ff6b39B244b50', @@ -60,4 +71,5 @@ export const OLAS_CONTRACTS: { [EvmChainId.Base]: BASE_OLAS_CONTRACTS, [EvmChainId.Mode]: MODE_OLAS_CONTRACTS, [EvmChainId.Celo]: CELO_OLAS_CONTRACTS, + [EvmChainId.Optimism]: OPTIMISM_OLAS_CONTRACTS, }; diff --git a/frontend/config/stakingPrograms/base.ts b/frontend/config/stakingPrograms/base.ts index b367a5462..f52f1a582 100644 --- a/frontend/config/stakingPrograms/base.ts +++ b/frontend/config/stakingPrograms/base.ts @@ -3,7 +3,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { STAKING_TOKEN_PROXY_ABI } from '@/abis/stakingTokenProxy'; import { AgentType } from '@/enums/Agent'; import { EvmChainId } from '@/enums/Chain'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { STAKING_PROGRAM_IDS } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; @@ -13,21 +13,24 @@ import { StakingProgramMap } from '.'; export const BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record = { - [StakingProgramId.MemeBaseAlpha2]: + [STAKING_PROGRAM_IDS.MemeBaseAlpha2]: '0xc653622FD75026a020995a1d8c8651316cBBc4dA', - [StakingProgramId.MemeBaseBeta]: + [STAKING_PROGRAM_IDS.MemeBaseBeta]: '0x6011E09e7c095e76980b22498d69dF18EB62BeD8', - [StakingProgramId.MemeBaseBeta2]: + [STAKING_PROGRAM_IDS.MemeBaseBeta2]: '0xfb7669c3AdF673b3A545Fa5acd987dbfdA805e22', - [StakingProgramId.MemeBaseBeta3]: + [STAKING_PROGRAM_IDS.MemeBaseBeta3]: '0xCA61633b03c54F64b6A7F1f9A9C0A6Feb231Cc4D', - [StakingProgramId.AgentsFun1]: '0x2585e63df7BD9De8e058884D496658a030b5c6ce', - [StakingProgramId.AgentsFun2]: '0x26FA75ef9Ccaa60E58260226A71e9d07564C01bF', - [StakingProgramId.AgentsFun3]: '0x4D4233EBF0473Ca8f34d105A6256A2389176F0Ce', + [STAKING_PROGRAM_IDS.AgentsFun1]: + '0x2585e63df7BD9De8e058884D496658a030b5c6ce', + [STAKING_PROGRAM_IDS.AgentsFun2]: + '0x26FA75ef9Ccaa60E58260226A71e9d07564C01bF', + [STAKING_PROGRAM_IDS.AgentsFun3]: + '0x4D4233EBF0473Ca8f34d105A6256A2389176F0Ce', }; export const BASE_STAKING_PROGRAMS: StakingProgramMap = { - [StakingProgramId.MemeBaseAlpha2]: { + [STAKING_PROGRAM_IDS.MemeBaseAlpha2]: { deprecated: true, chainId: EvmChainId.Base, name: 'MemeBase Alpha II', @@ -36,13 +39,17 @@ export const BASE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 100, }, activityChecker: - BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.MemeBaseAlpha2], + BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + STAKING_PROGRAM_IDS.MemeBaseAlpha2 + ], contract: new MulticallContract( - BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.MemeBaseAlpha2], + BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.MemeBaseAlpha2 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.MemeBaseBeta]: { + [STAKING_PROGRAM_IDS.MemeBaseBeta]: { deprecated: true, chainId: EvmChainId.Base, name: 'MemeBase Beta I', @@ -51,13 +58,15 @@ export const BASE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 100, }, activityChecker: - BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.MemeBaseBeta], + BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.MemeBaseBeta], contract: new MulticallContract( - BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.MemeBaseBeta], + BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.MemeBaseBeta + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.MemeBaseBeta2]: { + [STAKING_PROGRAM_IDS.MemeBaseBeta2]: { deprecated: true, chainId: EvmChainId.Base, name: 'MemeBase Beta II', @@ -66,13 +75,17 @@ export const BASE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 1000, }, activityChecker: - BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.MemeBaseBeta2], + BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + STAKING_PROGRAM_IDS.MemeBaseBeta2 + ], contract: new MulticallContract( - BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.MemeBaseBeta2], + BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.MemeBaseBeta2 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.MemeBaseBeta3]: { + [STAKING_PROGRAM_IDS.MemeBaseBeta3]: { deprecated: true, chainId: EvmChainId.Base, name: 'MemeBase Beta III', @@ -81,13 +94,17 @@ export const BASE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 5000, }, activityChecker: - BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.MemeBaseBeta3], + BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + STAKING_PROGRAM_IDS.MemeBaseBeta3 + ], contract: new MulticallContract( - BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.MemeBaseBeta3], + BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.MemeBaseBeta3 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.AgentsFun1]: { + [STAKING_PROGRAM_IDS.AgentsFun1]: { chainId: EvmChainId.Base, name: 'Agents.fun 1', agentsSupported: [AgentType.Memeooorr], @@ -97,13 +114,13 @@ export const BASE_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Marketplace, mech: MECHS[EvmChainId.Base][MechType.Marketplace].contract, activityChecker: - BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.AgentsFun1], + BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.AgentsFun1], contract: new MulticallContract( - BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.AgentsFun1], + BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[STAKING_PROGRAM_IDS.AgentsFun1], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.AgentsFun2]: { + [STAKING_PROGRAM_IDS.AgentsFun2]: { chainId: EvmChainId.Base, name: 'Agents.fun 2', agentsSupported: [AgentType.Memeooorr], @@ -113,13 +130,13 @@ export const BASE_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Marketplace, mech: MECHS[EvmChainId.Base][MechType.Marketplace].contract, activityChecker: - BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.AgentsFun2], + BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.AgentsFun2], contract: new MulticallContract( - BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.AgentsFun2], + BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[STAKING_PROGRAM_IDS.AgentsFun2], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.AgentsFun3]: { + [STAKING_PROGRAM_IDS.AgentsFun3]: { chainId: EvmChainId.Base, name: 'Agents.fun 3', agentsSupported: [AgentType.Memeooorr], @@ -129,9 +146,9 @@ export const BASE_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Marketplace, mech: MECHS[EvmChainId.Base][MechType.Marketplace].contract, activityChecker: - BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.AgentsFun3], + BASE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.AgentsFun3], contract: new MulticallContract( - BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.AgentsFun3], + BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[STAKING_PROGRAM_IDS.AgentsFun3], STAKING_TOKEN_PROXY_ABI, ), }, diff --git a/frontend/config/stakingPrograms/celo.ts b/frontend/config/stakingPrograms/celo.ts index 87810d04e..3fac66ad8 100644 --- a/frontend/config/stakingPrograms/celo.ts +++ b/frontend/config/stakingPrograms/celo.ts @@ -3,7 +3,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { STAKING_TOKEN_PROXY_ABI } from '@/abis/stakingTokenProxy'; import { AgentType } from '@/enums/Agent'; import { EvmChainId } from '@/enums/Chain'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { STAKING_PROGRAM_IDS } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; @@ -12,12 +12,12 @@ import { StakingProgramMap } from '.'; export const CELO_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record = { - [StakingProgramId.MemeCeloAlpha2]: + [STAKING_PROGRAM_IDS.MemeCeloAlpha2]: '0x95D12D193d466237Bc1E92a1a7756e4264f574AB', }; export const CELO_STAKING_PROGRAMS: StakingProgramMap = { - [StakingProgramId.MemeCeloAlpha2]: { + [STAKING_PROGRAM_IDS.MemeCeloAlpha2]: { chainId: EvmChainId.Celo, name: 'MemeCelo Alpha II', agentsSupported: [AgentType.AgentsFunCelo], @@ -25,9 +25,13 @@ export const CELO_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 100, }, activityChecker: - CELO_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.MemeCeloAlpha2], + CELO_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + STAKING_PROGRAM_IDS.MemeCeloAlpha2 + ], contract: new MulticallContract( - CELO_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.MemeCeloAlpha2], + CELO_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.MemeCeloAlpha2 + ], STAKING_TOKEN_PROXY_ABI, ), }, diff --git a/frontend/config/stakingPrograms/gnosis.ts b/frontend/config/stakingPrograms/gnosis.ts index 2d8c59878..e035f6e29 100644 --- a/frontend/config/stakingPrograms/gnosis.ts +++ b/frontend/config/stakingPrograms/gnosis.ts @@ -3,7 +3,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { STAKING_TOKEN_PROXY_ABI } from '@/abis/stakingTokenProxy'; import { AgentType } from '@/enums/Agent'; import { EvmChainId } from '@/enums/Chain'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { STAKING_PROGRAM_IDS } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; @@ -15,19 +15,25 @@ export const GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record< string, Address > = { - [StakingProgramId.PearlAlpha]: '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A', - [StakingProgramId.PearlBeta]: '0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d', - [StakingProgramId.PearlBeta2]: '0x1c2F82413666d2a3fD8bC337b0268e62dDF67434', - [StakingProgramId.PearlBeta3]: '0xBd59Ff0522aA773cB6074ce83cD1e4a05A457bc1', - [StakingProgramId.PearlBeta4]: '0x3052451e1eAee78e62E169AfdF6288F8791F2918', - [StakingProgramId.PearlBeta5]: '0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4', - [StakingProgramId.PearlBeta6]: '0x6C6D01e8eA8f806eF0c22F0ef7ed81D868C1aB39', - [StakingProgramId.PearlBetaMechMarketplace]: + [STAKING_PROGRAM_IDS.PearlAlpha]: + '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A', + [STAKING_PROGRAM_IDS.PearlBeta]: '0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d', + [STAKING_PROGRAM_IDS.PearlBeta2]: + '0x1c2F82413666d2a3fD8bC337b0268e62dDF67434', + [STAKING_PROGRAM_IDS.PearlBeta3]: + '0xBd59Ff0522aA773cB6074ce83cD1e4a05A457bc1', + [STAKING_PROGRAM_IDS.PearlBeta4]: + '0x3052451e1eAee78e62E169AfdF6288F8791F2918', + [STAKING_PROGRAM_IDS.PearlBeta5]: + '0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4', + [STAKING_PROGRAM_IDS.PearlBeta6]: + '0x6C6D01e8eA8f806eF0c22F0ef7ed81D868C1aB39', + [STAKING_PROGRAM_IDS.PearlBetaMechMarketplace]: '0xDaF34eC46298b53a3d24CBCb431E84eBd23927dA', } as const; export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { - [StakingProgramId.PearlAlpha]: { + [STAKING_PROGRAM_IDS.PearlAlpha]: { deprecated: true, name: 'Pearl Alpha', chainId: EvmChainId.Gnosis, @@ -38,13 +44,15 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Agent, mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, activityChecker: - GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.PearlAlpha], + GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.PearlAlpha], contract: new MulticallContract( - GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlAlpha], + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.PearlAlpha + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.PearlBeta]: { + [STAKING_PROGRAM_IDS.PearlBeta]: { chainId: EvmChainId.Gnosis, name: 'Pearl Beta', agentsSupported: [AgentType.PredictTrader], @@ -54,13 +62,13 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Agent, mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, activityChecker: - GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.PearlBeta], + GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.PearlBeta], contract: new MulticallContract( - GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta], + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[STAKING_PROGRAM_IDS.PearlBeta], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.PearlBeta2]: { + [STAKING_PROGRAM_IDS.PearlBeta2]: { chainId: EvmChainId.Gnosis, name: 'Pearl Beta 2', agentsSupported: [AgentType.PredictTrader], @@ -70,13 +78,15 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Agent, mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, activityChecker: - GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.PearlBeta2], + GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.PearlBeta2], contract: new MulticallContract( - GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta2], + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.PearlBeta2 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.PearlBeta3]: { + [STAKING_PROGRAM_IDS.PearlBeta3]: { chainId: EvmChainId.Gnosis, name: 'Pearl Beta 3', agentsSupported: [AgentType.PredictTrader], @@ -86,13 +96,15 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Agent, mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, activityChecker: - GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.PearlBeta3], + GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.PearlBeta3], contract: new MulticallContract( - GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta3], + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.PearlBeta3 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.PearlBeta4]: { + [STAKING_PROGRAM_IDS.PearlBeta4]: { chainId: EvmChainId.Gnosis, name: 'Pearl Beta 4', agentsSupported: [AgentType.PredictTrader], @@ -102,13 +114,15 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Agent, mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, activityChecker: - GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.PearlBeta4], + GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.PearlBeta4], contract: new MulticallContract( - GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta4], + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.PearlBeta4 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.PearlBeta5]: { + [STAKING_PROGRAM_IDS.PearlBeta5]: { chainId: EvmChainId.Gnosis, name: 'Pearl Beta 5', agentsSupported: [AgentType.PredictTrader], @@ -118,13 +132,15 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Agent, mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, activityChecker: - GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.PearlBeta5], + GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.PearlBeta5], contract: new MulticallContract( - GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta5], + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.PearlBeta5 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.PearlBeta6]: { + [STAKING_PROGRAM_IDS.PearlBeta6]: { chainId: EvmChainId.Gnosis, name: 'Pearl Beta 6', agentsSupported: [AgentType.PredictTrader], @@ -134,13 +150,15 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mechType: MechType.Agent, mech: MECHS[EvmChainId.Gnosis][MechType.Marketplace].contract, activityChecker: - GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.PearlBeta6], + GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.PearlBeta6], contract: new MulticallContract( - GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta6], + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.PearlBeta6 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.PearlBetaMechMarketplace]: { + [STAKING_PROGRAM_IDS.PearlBetaMechMarketplace]: { chainId: EvmChainId.Gnosis, name: 'Pearl Beta Mech Marketplace', agentsSupported: [AgentType.PredictTrader], @@ -151,11 +169,11 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mech: MECHS[EvmChainId.Gnosis][MechType.Marketplace].contract, activityChecker: GNOSIS_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ - StakingProgramId.PearlBetaMechMarketplace + STAKING_PROGRAM_IDS.PearlBetaMechMarketplace ], contract: new MulticallContract( GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ - StakingProgramId.PearlBetaMechMarketplace + STAKING_PROGRAM_IDS.PearlBetaMechMarketplace ], STAKING_TOKEN_PROXY_ABI, ), diff --git a/frontend/config/stakingPrograms/index.ts b/frontend/config/stakingPrograms/index.ts index 4f5e8c9c2..b36550fc7 100644 --- a/frontend/config/stakingPrograms/index.ts +++ b/frontend/config/stakingPrograms/index.ts @@ -2,7 +2,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { AgentType } from '@/enums/Agent'; import { EvmChainId } from '@/enums/Chain'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { STAKING_PROGRAM_IDS, StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; import { MechType } from '../mechs'; @@ -22,6 +22,10 @@ import { MODE_STAKING_PROGRAMS, MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES, } from './mode'; +import { + OPTIMISM_STAKING_PROGRAMS, + OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, +} from './optimism'; /** * Single non-chain specific staking program configuration @@ -51,6 +55,7 @@ export const STAKING_PROGRAMS: { [EvmChainId.Base]: BASE_STAKING_PROGRAMS, [EvmChainId.Mode]: MODE_STAKING_PROGRAMS, [EvmChainId.Celo]: CELO_STAKING_PROGRAMS, + [EvmChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS, }; export const STAKING_PROGRAM_ADDRESS: { @@ -60,13 +65,15 @@ export const STAKING_PROGRAM_ADDRESS: { [EvmChainId.Base]: BASE_STAKING_PROGRAMS_CONTRACT_ADDRESSES, [EvmChainId.Mode]: MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES, [EvmChainId.Celo]: CELO_STAKING_PROGRAMS_CONTRACT_ADDRESSES, + [EvmChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, }; export const DEFAULT_STAKING_PROGRAM_IDS: { [chainId in EvmChainId]: StakingProgramId; } = { - [EvmChainId.Gnosis]: StakingProgramId.PearlBeta, - [EvmChainId.Base]: StakingProgramId.MemeBaseAlpha2, - [EvmChainId.Mode]: StakingProgramId.ModiusAlpha, - [EvmChainId.Celo]: StakingProgramId.MemeCeloAlpha2, + [EvmChainId.Gnosis]: STAKING_PROGRAM_IDS.PearlBeta, + [EvmChainId.Base]: STAKING_PROGRAM_IDS.MemeBaseAlpha2, + [EvmChainId.Mode]: STAKING_PROGRAM_IDS.ModiusAlpha, + [EvmChainId.Celo]: STAKING_PROGRAM_IDS.MemeCeloAlpha2, + [EvmChainId.Optimism]: STAKING_PROGRAM_IDS.OptimusAlpha1, }; diff --git a/frontend/config/stakingPrograms/mode.ts b/frontend/config/stakingPrograms/mode.ts index 0c265887f..219ac3f40 100644 --- a/frontend/config/stakingPrograms/mode.ts +++ b/frontend/config/stakingPrograms/mode.ts @@ -3,7 +3,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { STAKING_TOKEN_PROXY_ABI } from '@/abis/stakingTokenProxy'; import { AgentType } from '@/enums/Agent'; import { EvmChainId } from '@/enums/Chain'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { STAKING_PROGRAM_IDS } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; @@ -12,21 +12,21 @@ import { StakingProgramMap } from '.'; export const MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record = { - [StakingProgramId.ModiusAlpha]: + [STAKING_PROGRAM_IDS.ModiusAlpha]: '0x534C0A05B6d4d28d5f3630D6D74857B253cf8332', - [StakingProgramId.OptimusAlpha]: - '0x5fc25f50e96857373c64dc0edb1abcbed4587e91', - [StakingProgramId.ModiusAlpha2]: + [STAKING_PROGRAM_IDS.ModiusAlpha2]: '0xeC013E68FE4B5734643499887941eC197fd757D0', - [StakingProgramId.ModiusAlpha3]: + [STAKING_PROGRAM_IDS.ModiusAlpha3]: '0x9034D0413D122015710f1744A19eFb1d7c2CEB13', - [StakingProgramId.ModiusAlpha4]: + [STAKING_PROGRAM_IDS.ModiusAlpha4]: '0x8BcAdb2c291C159F9385964e5eD95a9887302862', + [STAKING_PROGRAM_IDS.OptimusAlpha]: + '0x5fc25f50e96857373c64dc0edb1abcbed4587e91', }; export const MODE_STAKING_PROGRAMS: StakingProgramMap = { // modius alpha - [StakingProgramId.ModiusAlpha]: { + [STAKING_PROGRAM_IDS.ModiusAlpha]: { chainId: EvmChainId.Mode, name: 'Modius Alpha', agentsSupported: [AgentType.Modius], @@ -34,13 +34,13 @@ export const MODE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 40, }, activityChecker: - MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.ModiusAlpha], + MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.ModiusAlpha], contract: new MulticallContract( - MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.ModiusAlpha], + MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[STAKING_PROGRAM_IDS.ModiusAlpha], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.ModiusAlpha2]: { + [STAKING_PROGRAM_IDS.ModiusAlpha2]: { chainId: EvmChainId.Mode, name: 'Modius Alpha II', agentsSupported: [AgentType.Modius], @@ -48,13 +48,15 @@ export const MODE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 100, }, activityChecker: - MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.ModiusAlpha2], + MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.ModiusAlpha2], contract: new MulticallContract( - MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.ModiusAlpha2], + MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.ModiusAlpha2 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.ModiusAlpha3]: { + [STAKING_PROGRAM_IDS.ModiusAlpha3]: { chainId: EvmChainId.Mode, name: 'Modius Alpha III', agentsSupported: [AgentType.Modius], @@ -62,13 +64,15 @@ export const MODE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 1000, }, activityChecker: - MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.ModiusAlpha3], + MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.ModiusAlpha3], contract: new MulticallContract( - MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.ModiusAlpha3], + MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.ModiusAlpha3 + ], STAKING_TOKEN_PROXY_ABI, ), }, - [StakingProgramId.ModiusAlpha4]: { + [STAKING_PROGRAM_IDS.ModiusAlpha4]: { chainId: EvmChainId.Mode, name: 'Modius Alpha IV', agentsSupported: [AgentType.Modius], @@ -76,14 +80,16 @@ export const MODE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 5000, }, activityChecker: - MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.ModiusAlpha4], + MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.ModiusAlpha4], contract: new MulticallContract( - MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.ModiusAlpha4], + MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.ModiusAlpha4 + ], STAKING_TOKEN_PROXY_ABI, ), }, - //optimus alpha - [StakingProgramId.OptimusAlpha]: { + // optimus alpha + [STAKING_PROGRAM_IDS.OptimusAlpha]: { chainId: EvmChainId.Mode, name: 'Optimus Alpha', agentsSupported: [AgentType.Modius], @@ -91,9 +97,11 @@ export const MODE_STAKING_PROGRAMS: StakingProgramMap = { [TokenSymbol.OLAS]: 40, }, activityChecker: - MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[StakingProgramId.OptimusAlpha], + MODE_STAKING_PROGRAMS_ACTIVITY_CHECKERS[STAKING_PROGRAM_IDS.OptimusAlpha], contract: new MulticallContract( - MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.OptimusAlpha], + MODE_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + STAKING_PROGRAM_IDS.OptimusAlpha + ], STAKING_TOKEN_PROXY_ABI, ), }, diff --git a/frontend/config/stakingPrograms/optimism.ts b/frontend/config/stakingPrograms/optimism.ts new file mode 100644 index 000000000..4d91354b5 --- /dev/null +++ b/frontend/config/stakingPrograms/optimism.ts @@ -0,0 +1,101 @@ +import { Contract as MulticallContract } from 'ethers-multicall'; + +import { STAKING_TOKEN_PROXY_ABI } from '@/abis/stakingTokenProxy'; +import { AgentType } from '@/enums/Agent'; +import { EvmChainId } from '@/enums/Chain'; +import { + OPTIMISM_STAKING_PROGRAM_IDS, + OptimismStakingProgramId, +} from '@/enums/StakingProgram'; +import { TokenSymbol } from '@/enums/Token'; +import { Address } from '@/types/Address'; + +import { OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS } from '../activityCheckers'; +import { StakingProgramConfig } from '.'; + +export const OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record< + OptimismStakingProgramId, + Address +> = { + [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha1]: + '0x88996bbdE7f982D93214881756840cE2c77C4992', + // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2]: + // '0xBCA056952D2A7a8dD4A002079219807CFDF9fd29', + // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3]: + // '0x0f69f35652B1acdbD769049334f1AC580927E139', + // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4]: + // '0x6891Cf116f9a3bDbD1e89413118eF81F69D298C3', +}; + +export const OPTIMISM_STAKING_PROGRAMS: { + [stakingProgramId in OptimismStakingProgramId]: StakingProgramConfig; +} = { + [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha1]: { + chainId: EvmChainId.Optimism, + name: 'Optimus Alpha', + agentsSupported: [AgentType.Optimus], + stakingRequirements: { [TokenSymbol.OLAS]: 40 }, + activityChecker: + OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha1 + ], + contract: new MulticallContract( + OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha1 + ], + STAKING_TOKEN_PROXY_ABI, + ), + }, + // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2]: { + // chainId: EvmChainId.Optimism, + // name: 'Optimus Alpha II', + // agentsSupported: [AgentType.Optimus], + // stakingRequirements: { [TokenSymbol.OLAS]: 100 }, + // activityChecker: + // OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2 + // ], + // contract: new MulticallContract( + // OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2 + // ], + // STAKING_TOKEN_PROXY_ABI, + // ), + // }, + // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3]: { + // chainId: EvmChainId.Optimism, + // name: 'Optimus Alpha III', + // agentsSupported: [AgentType.Optimus], + // stakingRequirements: { + // [TokenSymbol.OLAS]: 1000, + // }, + // activityChecker: + // OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3 + // ], + // contract: new MulticallContract( + // OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3 + // ], + // STAKING_TOKEN_PROXY_ABI, + // ), + // }, + // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4]: { + // chainId: EvmChainId.Optimism, + // name: 'Optimus Alpha IV', + // agentsSupported: [AgentType.Optimus], + // stakingRequirements: { + // [TokenSymbol.OLAS]: 5000, + // }, + // activityChecker: + // OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4 + // ], + // contract: new MulticallContract( + // OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4 + // ], + // STAKING_TOKEN_PROXY_ABI, + // ), + // }, +}; diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index 0241de47f..b1277594a 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -115,11 +115,37 @@ export const MODE_TOKEN_CONFIG: ChainTokenConfig = { }, }; +export const OPTIMISM_TOKEN_CONFIG: ChainTokenConfig = { + [TokenSymbol.ETH]: { + tokenType: TokenType.NativeGas, + symbol: TokenSymbol.ETH, + decimals: 18, + }, + [TokenSymbol.OLAS]: { + tokenType: TokenType.Erc20, + symbol: TokenSymbol.OLAS, + decimals: 18, + address: '0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527', + }, + /** + * @warning USDC is a special case, it has 6 decimals, not 18. + * @link https://optimism.blockscout.com/address/0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85?tab=read_write_proxy&source_address=0xdEd3b9a8DBeDC2F9CB725B55d0E686A81E6d06dC#0x313ce567 + * @note When parsing or formatting units, use `decimals` (6) instead of the standard `ether` sizing (10^18). + */ + [TokenSymbol.USDC]: { + tokenType: TokenType.Erc20, + symbol: TokenSymbol.USDC, + decimals: 6, + address: '0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85', + }, +}; + export const TOKEN_CONFIG: Record = { [EvmChainId.Gnosis]: GNOSIS_TOKEN_CONFIG, [EvmChainId.Base]: BASE_TOKEN_CONFIG, [EvmChainId.Mode]: MODE_TOKEN_CONFIG, [EvmChainId.Celo]: CELO_TOKEN_CONFIG, + [EvmChainId.Optimism]: OPTIMISM_TOKEN_CONFIG, } as const; /** diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index e7ddbd6a2..98bca5e9a 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -1,9 +1,9 @@ import { ethers } from 'ethers'; import { EnvProvisionType, MiddlewareChain, ServiceTemplate } from '@/client'; -import { MODE_TOKEN_CONFIG } from '@/config/tokens'; +import { MODE_TOKEN_CONFIG, OPTIMISM_TOKEN_CONFIG } from '@/config/tokens'; import { AgentType } from '@/enums/Agent'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { STAKING_PROGRAM_IDS } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { parseEther, parseUnits } from '@/utils/numberFormatters'; @@ -18,7 +18,7 @@ export const PREDICT_SERVICE_TEMPLATE: ServiceTemplate = { home_chain: MiddlewareChain.GNOSIS, configurations: { [MiddlewareChain.GNOSIS]: { - staking_program_id: StakingProgramId.PearlBeta, // default, may be overwritten + staking_program_id: STAKING_PROGRAM_IDS.PearlBeta, // default, may be overwritten nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', rpc: 'http://localhost:8545', // overwritten agent_id: 14, @@ -202,7 +202,7 @@ export const AGENTS_FUN_BASE_TEMPLATE: ServiceTemplate = { home_chain: MiddlewareChain.BASE, configurations: { [MiddlewareChain.BASE]: { - staking_program_id: StakingProgramId.AgentsFun1, // default, may be overwritten + staking_program_id: STAKING_PROGRAM_IDS.AgentsFun1, // default, may be overwritten nft: 'bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', rpc: 'http://localhost:8545', // overwritten agent_id: 43, @@ -231,7 +231,7 @@ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = { home_chain: MiddlewareChain.CELO, configurations: { [MiddlewareChain.CELO]: { - staking_program_id: StakingProgramId.MemeCeloAlpha2, // default, may be overwritten + staking_program_id: STAKING_PROGRAM_IDS.MemeCeloAlpha2, // default, may be overwritten nft: 'bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', rpc: 'http://localhost:8545', // overwritten agent_id: 43, @@ -261,7 +261,7 @@ export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { home_chain: MiddlewareChain.MODE, configurations: { [MiddlewareChain.MODE]: { - staking_program_id: StakingProgramId.ModiusAlpha, // default, may be overwritten + staking_program_id: STAKING_PROGRAM_IDS.ModiusAlpha, // default, may be overwritten nft: 'bafybeiafjcy63arqkfqbtjqpzxyeia2tscpbyradb4zlpzhgc3xymwmmtu', rpc: 'http://localhost:8545', // overwritten agent_id: 40, @@ -401,11 +401,141 @@ export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { }, } as const; +export const OPTIMUS_SERVICE_TEMPLATE: ServiceTemplate = { + agentType: AgentType.Optimus, + name: 'Optimus - Optimism', + hash: 'bafybeiaatol6ujhey6wlijc3uk57k74bj4yqaehobpfrch7kjxnvghpqgy', + description: 'Optimus service deployment on Optimism network', + image: + 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', + service_version: 'v0.3.15', + home_chain: MiddlewareChain.OPTIMISM, + configurations: { + [MiddlewareChain.OPTIMISM]: { + staking_program_id: STAKING_PROGRAM_IDS.OptimusAlpha, // default, may be overwritten + nft: 'bafybeiafjcy63arqkfqbtjqpzxyeia2tscpbyradb4zlpzhgc3xymwmmtu', + rpc: 'http://localhost:8545', // overwritten + agent_id: 40, + threshold: 1, + use_staking: true, + cost_of_bond: +parseEther(20), + monthly_gas_estimate: +parseEther(0.011), + fund_requirements: { + [ethers.constants.AddressZero]: { + agent: +parseEther(0.0007), + safe: +parseEther(0.0057), + }, + [OPTIMISM_TOKEN_CONFIG[TokenSymbol.USDC].address as string]: { + agent: 0, + safe: +parseUnits( + 16, + OPTIMISM_TOKEN_CONFIG[TokenSymbol.USDC].decimals, + ), + }, + }, + }, + }, + env_variables: { + OPTIMISM_LEDGER_RPC: { + name: 'Optimism ledger RPC', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, + }, + SAFE_CONTRACT_ADDRESSES: { + name: 'Safe contract address', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, + }, + TENDERLY_ACCESS_KEY: { + name: 'Tenderly access key', + description: '', + value: '', + provision_type: EnvProvisionType.USER, + }, + TENDERLY_ACCOUNT_SLUG: { + name: 'Tenderly account slug', + description: '', + value: '', + provision_type: EnvProvisionType.USER, + }, + TENDERLY_PROJECT_SLUG: { + name: 'Tenderly project slug', + description: '', + value: '', + provision_type: EnvProvisionType.USER, + }, + STAKING_TOKEN_CONTRACT_ADDRESS: { + name: 'Staking token contract address', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, + }, + COINGECKO_API_KEY: { + name: 'Coingecko API key', + description: '', + value: '', + provision_type: EnvProvisionType.USER, + }, + GENAI_API_KEY: { + name: 'Gemini API key', + description: '', + value: '', + provision_type: EnvProvisionType.USER, + }, + STAKING_CHAIN: { + name: 'Staking chain', + description: '', + value: 'optimism', + provision_type: EnvProvisionType.FIXED, + }, + ACTIVITY_CHECKER_CONTRACT_ADDRESS: { + name: 'Staking activity checker contract address', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, + }, + TARGET_INVESTMENT_CHAINS: { + name: 'Target investment chains', + description: '', + value: '["optimism"]', + provision_type: EnvProvisionType.FIXED, + }, + INITIAL_ASSETS: { + name: 'Initial assets', + description: '', + value: + '{"optimism":{"0x0000000000000000000000000000000000000000":"ETH","0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85":"USDC"}}', + provision_type: EnvProvisionType.FIXED, + }, + INIT_FALLBACK_GAS: { + name: 'Init fallback gas', + description: '', + value: '250000', + provision_type: EnvProvisionType.FIXED, + }, + STORE_PATH: { + name: 'Store path', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, + }, + RESET_PAUSE_DURATION: { + name: 'Reset pause duration', + description: '', + value: '300', + provision_type: EnvProvisionType.FIXED, + }, + }, +} as const; + export const SERVICE_TEMPLATES: ServiceTemplate[] = [ PREDICT_SERVICE_TEMPLATE, AGENTS_FUN_BASE_TEMPLATE, MODIUS_SERVICE_TEMPLATE, AGENTS_FUN_CELO_TEMPLATE, + OPTIMUS_SERVICE_TEMPLATE, ] as const; export const getServiceTemplates = (): ServiceTemplate[] => SERVICE_TEMPLATES; diff --git a/frontend/constants/urls.ts b/frontend/constants/urls.ts index 52cba1752..4499829b1 100644 --- a/frontend/constants/urls.ts +++ b/frontend/constants/urls.ts @@ -1,4 +1,4 @@ -import { MiddlewareChain } from '@/client'; +import { MiddlewareChain, SupportedMiddlewareChain } from '@/client'; import { EvmChainId } from '@/enums/Chain'; type Url = `http${'s' | ''}://${string}`; @@ -15,6 +15,8 @@ const SWAP_MODE_URL: Url = 'https://balancer.fi/swap/mode/0xd988097fb8612cc24eec14542bc03424c656005f/0xcfd1d50ce23c46d3cf6407487b2f8934e96dc8f9'; const SWAP_CELO_URL: Url = 'https://app.ubeswap.org/#/swap?inputCurrency=0x471ece3750da237f93b8e339c536989b8978a438&outputCurrency=0xacffae8e57ec6e394eb1b41939a8cf7892dbdc51'; +const SWAP_OPTIMISM_URL: Url = + 'https://balancer.fi/pools/optimism/v2/0x5bb3e58887264b667f915130fd04bbb56116c27800020000000000000000012a'; // olas.network export const OPERATE_URL: Url = 'https://olas.network/operate'; @@ -23,7 +25,10 @@ export const TERMS_AND_CONDITIONS_URL: Url = 'https://olas.network/pearl-terms'; export const DOWNLOAD_URL: Url = 'https://olas.network/operate#download'; // thegraph -export const REWARDS_HISTORY_SUBGRAPH_URLS_BY_EVM_CHAIN = { +export const REWARDS_HISTORY_SUBGRAPH_URLS_BY_EVM_CHAIN: Record< + EvmChainId, + Url +> = { [EvmChainId.Gnosis]: 'https://gateway.thegraph.com/api/5c035877a4af18d178c96afe55ed41ae/subgraphs/id/F3iqL2iw5UTrP1qbb4S694pGEkBwzoxXp1TRikB2K4e', [EvmChainId.Base]: @@ -32,6 +37,8 @@ export const REWARDS_HISTORY_SUBGRAPH_URLS_BY_EVM_CHAIN = { 'https://gateway.thegraph.com/api/5c035877a4af18d178c96afe55ed41ae/subgraphs/id/Fe6oYUKbSGP7a16NowseTU82MVG9D2xWbBUCz4MPB4d4', [EvmChainId.Celo]: 'https://api.studio.thegraph.com/query/67875/olas-celo-staking/version/latest', + [EvmChainId.Optimism]: + 'https://gateway.thegraph.com/api/5c035877a4af18d178c96afe55ed41ae/subgraphs/id/2fe1izA4aVvBHVwbPzP1BqxLkoR9ebygWM9iHXwLCnPE', }; // discord @@ -50,6 +57,7 @@ const GNOSIS_EXPLORER_URL: Url = 'https://gnosisscan.io'; const BASE_EXPLORER_URL: Url = 'https://basescan.org'; const MODE_EXPLORER_URL: Url = 'https://modescan.io'; const CELO_EXPLORER_URL: Url = 'https://celoscan.io'; +const OPTIMISM_EXPLORER_URL: Url = 'https://optimistic.etherscan.io'; // others export const TENDERLY_URL: string = 'https://tenderly.co'; @@ -59,28 +67,31 @@ export const COINGECKO_DEMO_API_KEY: string = export const GEMINI_API_URL: string = 'https://aistudio.google.com/app/apikey'; export const EXPLORER_URL_BY_MIDDLEWARE_CHAIN: Record< - string | MiddlewareChain, + SupportedMiddlewareChain, Url > = { [MiddlewareChain.GNOSIS]: GNOSIS_EXPLORER_URL, [MiddlewareChain.BASE]: BASE_EXPLORER_URL, [MiddlewareChain.MODE]: MODE_EXPLORER_URL, [MiddlewareChain.CELO]: CELO_EXPLORER_URL, + [MiddlewareChain.OPTIMISM]: OPTIMISM_EXPLORER_URL, }; export const BLOCKSCOUT_URL_BY_MIDDLEWARE_CHAIN: Record< - string | MiddlewareChain, + SupportedMiddlewareChain, Url > = { [MiddlewareChain.GNOSIS]: 'https://gnosis.blockscout.com', [MiddlewareChain.BASE]: 'https://base.blockscout.com', [MiddlewareChain.MODE]: 'https://explorer.mode.network', [MiddlewareChain.CELO]: 'https://celo.blockscout.com', + [MiddlewareChain.OPTIMISM]: 'https://optimism.blockscout.com', }; -export const SWAP_URL_BY_EVM_CHAIN: Record = { +export const SWAP_URL_BY_EVM_CHAIN: Record = { [EvmChainId.Gnosis]: COW_SWAP_GNOSIS_XDAI_OLAS_URL, [EvmChainId.Base]: SWAP_BASE_URL, [EvmChainId.Mode]: SWAP_MODE_URL, [EvmChainId.Celo]: SWAP_CELO_URL, + [EvmChainId.Optimism]: SWAP_OPTIMISM_URL, }; diff --git a/frontend/context/ElectronApiProvider.tsx b/frontend/context/ElectronApiProvider.tsx index 4575f8a84..b8ef56589 100644 --- a/frontend/context/ElectronApiProvider.tsx +++ b/frontend/context/ElectronApiProvider.tsx @@ -1,7 +1,7 @@ import { get } from 'lodash'; import { createContext, PropsWithChildren } from 'react'; -import { AgentHealthCheck } from '@/types/Agent'; +import { AgentHealthCheckResponse } from '@/types/Agent'; import { XCookie } from '@/types/Cookies'; import { ElectronStore, ElectronTrayIconStatus } from '@/types/ElectronApi'; @@ -53,7 +53,7 @@ type ElectronApiContextProps = { email: string; }) => Promise<{ success: boolean; cookies?: XCookie[] }>; healthCheck?: () => Promise< - { response: AgentHealthCheck | null } | { error: string } + { response: AgentHealthCheckResponse | null } | { error: string } >; agentActivityWindow?: Partial; }; diff --git a/frontend/context/StakingContractDetailsProvider.tsx b/frontend/context/StakingContractDetailsProvider.tsx index 95dc4be9c..bbc8236f3 100644 --- a/frontend/context/StakingContractDetailsProvider.tsx +++ b/frontend/context/StakingContractDetailsProvider.tsx @@ -102,7 +102,6 @@ const useStakingContractDetailsByStakingProgram = ({ * Request staking contract details * if service is present, request it's info and states on the staking contract */ - const promises: Promise< StakingContractDetails | ServiceStakingDetails | undefined >[] = [ diff --git a/frontend/enums/Agent.ts b/frontend/enums/Agent.ts index 19d15876a..daf798c2a 100644 --- a/frontend/enums/Agent.ts +++ b/frontend/enums/Agent.ts @@ -3,6 +3,7 @@ export const AgentType = { Memeooorr: 'memeooorr', AgentsFunCelo: 'agents-fun-celo', Modius: 'modius', + Optimus: 'optimus', } as const; export type AgentType = (typeof AgentType)[keyof typeof AgentType]; diff --git a/frontend/enums/Chain.ts b/frontend/enums/Chain.ts index e491d5aa4..74e791b01 100644 --- a/frontend/enums/Chain.ts +++ b/frontend/enums/Chain.ts @@ -3,6 +3,7 @@ export enum EvmChainId { Base = 8453, Mode = 34443, Celo = 42220, + Optimism = 10, } export const EvmChainName = { @@ -10,13 +11,14 @@ export const EvmChainName = { [EvmChainId.Base]: 'Base', [EvmChainId.Mode]: 'Mode', [EvmChainId.Celo]: 'Celo', -}; + [EvmChainId.Optimism]: 'Optimism', +} as const; export enum AllEvmChainId { + Ethereum = 1, Gnosis = EvmChainId.Gnosis, Base = EvmChainId.Base, Mode = EvmChainId.Mode, Celo = EvmChainId.Celo, - Ethereum = 1, - Optimism = 10, + Optimism = EvmChainId.Optimism, } diff --git a/frontend/enums/StakingProgram.ts b/frontend/enums/StakingProgram.ts index db2f6cc29..aab958ebe 100644 --- a/frontend/enums/StakingProgram.ts +++ b/frontend/enums/StakingProgram.ts @@ -1,23 +1,55 @@ -export enum StakingProgramId { - PearlAlpha = 'pearl_alpha', - PearlBeta = 'pearl_beta', - PearlBeta2 = 'pearl_beta_2', - PearlBeta3 = 'pearl_beta_3', - PearlBeta4 = 'pearl_beta_4', - PearlBeta5 = 'pearl_beta_5', - PearlBeta6 = 'pearl_beta_6', - PearlBetaMechMarketplace = 'pearl_beta_mech_marketplace', - OptimusAlpha = 'optimus_alpha', - MemeBaseAlpha2 = 'meme_base_alpha_2', - MemeBaseBeta = 'meme_base_beta', - MemeBaseBeta2 = 'meme_base_beta_2', - MemeBaseBeta3 = 'meme_base_beta_3', - MemeCeloAlpha2 = 'meme_celo_alpha_2', - AgentsFun1 = 'agents_fun_1', - AgentsFun2 = 'agents_fun_2', - AgentsFun3 = 'agents_fun_3', - ModiusAlpha = 'modius_alpha', - ModiusAlpha2 = 'modius_alpha_2', - ModiusAlpha3 = 'modius_alpha_3', - ModiusAlpha4 = 'modius_alpha_4', -} +import { ValueOf } from '@/types/Util'; + +const GNOSIS_STAKING_PROGRAM_IDS = { + PearlAlpha: 'pearl_alpha', + PearlBeta: 'pearl_beta', + PearlBeta2: 'pearl_beta_2', + PearlBeta3: 'pearl_beta_3', + PearlBeta4: 'pearl_beta_4', + PearlBeta5: 'pearl_beta_5', + PearlBeta6: 'pearl_beta_6', + PearlBetaMechMarketplace: 'pearl_beta_mech_marketplace', +} as const; + +const BASE_STAKING_PROGRAM_IDS = { + MemeBaseAlpha2: 'meme_base_alpha_2', + MemeBaseBeta: 'meme_base_beta', + MemeBaseBeta2: 'meme_base_beta_2', + MemeBaseBeta3: 'meme_base_beta_3', + MemeCeloAlpha2: 'meme_celo_alpha_2', + AgentsFun1: 'agents_fun_1', + AgentsFun2: 'agents_fun_2', + AgentsFun3: 'agents_fun_3', +} as const; + +const MODE_STAKING_PROGRAM_IDS = { + ModiusAlpha: 'modius_alpha', + ModiusAlpha2: 'modius_alpha_2', + ModiusAlpha3: 'modius_alpha_3', + ModiusAlpha4: 'modius_alpha_4', + OptimusAlpha: 'optimus_alpha', +} as const; + +export const OPTIMISM_STAKING_PROGRAM_IDS = { + OptimusAlpha1: 'optimus_alpha', + // OptimusAlpha2: 'optimus_alpha_2', + // OptimusAlpha3: 'optimus_alpha_3', + // OptimusAlpha4: 'optimus_alpha_4', +} as const; + +export type OptimismStakingProgramId = ValueOf< + typeof OPTIMISM_STAKING_PROGRAM_IDS +>; + +/** + * @link https://github.com/valory-xyz/olas-operate-middleware/blob/9ca362f302ae749dd99b236d062ccc5c722acabf/operate/ledger/profiles.py#L115 + * Refer the above link for the list of staking program ids. + */ +export const STAKING_PROGRAM_IDS = { + ...GNOSIS_STAKING_PROGRAM_IDS, + ...BASE_STAKING_PROGRAM_IDS, + ...MODE_STAKING_PROGRAM_IDS, + ...OPTIMISM_STAKING_PROGRAM_IDS, +} as const; + +export type StakingProgramId = ValueOf; diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index 6f60872e7..bf68e7c6c 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -73,6 +73,17 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'backup-via-safe': false, // temporarily hidden until mode is available on safe https://app.safe.global/new-safe/create 'agent-settings': true, }, + [AgentType.Optimus]: { + 'manage-wallet': false, + 'withdraw-funds': false, + 'last-transactions': false, + 'rewards-streak': false, + 'staking-contract-section': false, + 'low-funds': false, + 'agent-activity': false, + 'backup-via-safe': false, // temporarily hidden until mode is available on safe https://app.safe.global/new-safe/create + 'agent-settings': false, + }, }); type FeatureFlagReturn = diff --git a/frontend/public/agent-optimus-icon.png b/frontend/public/agent-optimus-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1e8d757661d53547ccfdf39e65cf52b45cc828d4 GIT binary patch literal 47446 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 literal 0 HcmV?d00001 diff --git a/frontend/public/setup-agent-optimus-1.png b/frontend/public/setup-agent-optimus-1.png new file mode 100644 index 0000000000000000000000000000000000000000..5b505dfd33003509eb09f482c5a15e38bca5c282 GIT binary patch literal 38724 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 literal 0 HcmV?d00001 diff --git a/frontend/public/setup-agent-optimus-2.png b/frontend/public/setup-agent-optimus-2.png new file mode 100644 index 0000000000000000000000000000000000000000..63a63e07b0b013f2ebd0e7fdbc5a705d0c367cb7 GIT binary patch literal 32062 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 oaZpT@XAi=>xjV*d`cL2w3_kqgtT@+N%$~^H Math.floor(Date.now() / 1000); + +export abstract class OptimismService extends StakedAgentService { + static getAgentStakingRewardsInfo = async ({ + agentMultisigAddress, + serviceId, + stakingProgramId, + chainId = EvmChainId.Optimism, + }: { + agentMultisigAddress: Address; + serviceId: number; + stakingProgramId: StakingProgramId; // TODO: should infer type OptimismStakingProgramId + chainId?: EvmChainId; + }): Promise => { + if (!agentMultisigAddress) return; + if (!isValidServiceId(serviceId)) return; + + const stakingProgramConfig = STAKING_PROGRAMS[chainId][stakingProgramId]; + if (!stakingProgramConfig) throw new Error('Staking program not found'); + + const { activityChecker, contract: stakingTokenProxyContract } = + stakingProgramConfig; + + const provider = PROVIDERS[chainId].multicallProvider; + const contractCalls = [ + stakingTokenProxyContract.getServiceInfo(serviceId), + stakingTokenProxyContract.livenessPeriod(), + stakingTokenProxyContract.rewardsPerSecond(), + stakingTokenProxyContract.calculateStakingReward(serviceId), + stakingTokenProxyContract.minStakingDeposit(), + stakingTokenProxyContract.tsCheckpoint(), + activityChecker.livenessRatio(), + activityChecker.getMultisigNonces(agentMultisigAddress), + ]; + const multicallResponse = await provider.all(contractCalls); + + const [ + serviceInfo, + livenessPeriod, + rewardsPerSecond, + accruedStakingReward, + minStakingDeposit, + tsCheckpoint, + livenessRatio, + currentMultisigNonces, + ] = multicallResponse; + + const lastMultisigNonces = serviceInfo[2]; + const isServiceStaked = lastMultisigNonces.length > 0; + + // Calculate the number of requests required to be eligible for rewards + const secondsSinceCheckpoint = getNowInSeconds() - tsCheckpoint; + const effectivePeriod = Math.max(livenessPeriod, secondsSinceCheckpoint); + const requiredRequests = + (Math.ceil(effectivePeriod) * livenessRatio) / 1e18 + + REQUESTS_SAFETY_MARGIN; + + // Determine how many requests the service has handled since last checkpoint + const eligibleRequests = isServiceStaked + ? currentMultisigNonces[0] - lastMultisigNonces[0] + : 0; + + // Check eligibility for rewards + const isEligibleForRewards = eligibleRequests >= requiredRequests; + + // Available rewards for the current epoch + const expectedEpochRewards = rewardsPerSecond * livenessPeriod; + const lateCheckpointRewards = rewardsPerSecond * secondsSinceCheckpoint; + const availableRewardsForEpoch = Math.max( + expectedEpochRewards, + lateCheckpointRewards, + ); + + // Minimum amount that must be staked (double the minimum deposit) + const minimumStakedAmount = + parseFloat(ethers.utils.formatEther(`${minStakingDeposit}`)) * 2; + + return { + serviceInfo, + livenessPeriod, + livenessRatio, + rewardsPerSecond, + isEligibleForRewards, + availableRewardsForEpoch, + accruedServiceStakingRewards: parseFloat( + ethers.utils.formatEther(`${accruedStakingReward}`), + ), + minimumStakedAmount, + } satisfies StakingRewardsInfo; + }; + + static getAvailableRewardsForEpoch = async ( + stakingProgramId: StakingProgramId, + chainId: EvmChainId = EvmChainId.Optimism, + ): Promise => { + const stakingTokenProxy = + STAKING_PROGRAMS[chainId][stakingProgramId]?.contract; + if (!stakingTokenProxy) return; + + const { multicallProvider } = PROVIDERS[chainId]; + const contractCalls = [ + stakingTokenProxy.rewardsPerSecond(), + stakingTokenProxy.livenessPeriod(), // epoch length + stakingTokenProxy.tsCheckpoint(), // last checkpoint timestamp + ]; + const multicallResponse = await multicallProvider.all(contractCalls); + + const [rewardsPerSecond, livenessPeriod, tsCheckpoint] = multicallResponse; + const expectedRewards = rewardsPerSecond * livenessPeriod; + const lateCheckpointRewards = + rewardsPerSecond * (getNowInSeconds() - tsCheckpoint); + + return BigInt(Math.max(expectedRewards, lateCheckpointRewards)); + }; + + /** + * Get service details by it's NftTokenId on a provided staking contract + */ + static getServiceStakingDetails = async ( + serviceNftTokenId: number, + stakingProgramId: StakingProgramId, + chainId: EvmChainId = EvmChainId.Optimism, + ): Promise => { + const { multicallProvider } = PROVIDERS[chainId]; + + const { contract: stakingTokenProxy } = + STAKING_PROGRAMS[chainId][stakingProgramId]; + + const contractCalls = [ + stakingTokenProxy.getServiceInfo(serviceNftTokenId), + stakingTokenProxy.getStakingState(serviceNftTokenId), + ]; + const multicallResponse = await multicallProvider.all(contractCalls); + const [serviceInfo, serviceStakingState] = multicallResponse; + + return { + serviceStakingStartTime: serviceInfo.tsStart.toNumber(), + serviceStakingState, + }; + }; + + /** + * Get staking contract info by staking program name + * eg. Alpha, Beta, Beta2 + */ + static getStakingContractDetails = async ( + stakingProgramId: StakingProgramId, + chainId: EvmChainId, + ): Promise => { + const { multicallProvider } = PROVIDERS[chainId]; + + const stakingTokenProxy = + OPTIMISM_STAKING_PROGRAMS[stakingProgramId as OptimismStakingProgramId] + ?.contract; + if (!stakingTokenProxy) return; + + const contractCalls = [ + stakingTokenProxy.availableRewards(), + stakingTokenProxy.maxNumServices(), + stakingTokenProxy.getServiceIds(), + stakingTokenProxy.minStakingDuration(), + stakingTokenProxy.minStakingDeposit(), + stakingTokenProxy.rewardsPerSecond(), + stakingTokenProxy.numAgentInstances(), + stakingTokenProxy.livenessPeriod(), + stakingTokenProxy.epochCounter(), + ]; + const multicallResponse = await multicallProvider.all(contractCalls); + + const [ + availableRewardsInBN, + maxNumServicesInBN, + getServiceIdsInBN, + minStakingDurationInBN, + minStakingDeposit, + rewardsPerSecond, + numAgentInstances, + livenessPeriod, + epochCounter, + ] = multicallResponse; + + const availableRewards = parseFloat( + ethers.utils.formatUnits(availableRewardsInBN, 18), + ); + const serviceIds: number[] = getServiceIdsInBN.map((id: bigint) => + Number(id), + ); + const maxNumServices: number = maxNumServicesInBN.toNumber(); + + // Calculate annual rewards (used for APY) + const rewardsPerYear = rewardsPerSecond.mul(ONE_YEAR); + + // APY + let apy = 0; + if (rewardsPerSecond.gt(0) && minStakingDeposit.gt(0)) { + const annualPercentage = rewardsPerYear.mul(100).div(minStakingDeposit); + apy = Number(annualPercentage) / (1 + numAgentInstances.toNumber()); + } + + // Required OLAS stake (min deposit per agent instance) + const stakeRequiredInWei = minStakingDeposit.add( + minStakingDeposit.mul(numAgentInstances), + ); + const olasStakeRequired = Number(formatEther(stakeRequiredInWei)); + + // Rewards earned per work period + const rewardsPerWorkPeriod = + Number(formatEther(rewardsPerSecond as bigint)) * + livenessPeriod.toNumber(); + + return { + availableRewards, + maxNumServices, + serviceIds, + minimumStakingDuration: minStakingDurationInBN.toNumber(), + minStakingDeposit: parseFloat( + ethers.utils.formatEther(minStakingDeposit), + ), + apy, + olasStakeRequired, + rewardsPerWorkPeriod, + epochCounter: epochCounter.toNumber(), + }; + }; +} diff --git a/frontend/types/Agent.ts b/frontend/types/Agent.ts index 7be69419f..986c8fb6b 100644 --- a/frontend/types/Agent.ts +++ b/frontend/types/Agent.ts @@ -1,20 +1,28 @@ -import { MiddlewareChain } from '@/client'; +import { SupportedMiddlewareChain } from '@/client'; import { EvmChainId } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; +import { AgentsFunBaseService } from '@/service/agents/AgentsFunBase'; +import { ModiusService } from '@/service/agents/Modius'; +import { OptimismService } from '@/service/agents/Optimism'; import { PredictTraderService } from '@/service/agents/PredictTrader'; export type AgentConfig = { name: string; evmHomeChainId: EvmChainId; - middlewareHomeChainId: MiddlewareChain; + middlewareHomeChainId: SupportedMiddlewareChain; requiresAgentSafesOn: EvmChainId[]; requiresMasterSafesOn: EvmChainId[]; additionalRequirements?: Partial< Record>> >; - serviceApi: typeof PredictTraderService; + serviceApi: + | typeof PredictTraderService + | typeof ModiusService + | typeof OptimismService + | typeof AgentsFunBaseService; displayName: string; description: string; + /** Whether the agent is enabled and can be shown in the UI */ isAgentEnabled: boolean; /** If agent is enabled but not yet available to use */ isComingSoon?: boolean; @@ -25,7 +33,7 @@ export type AgentConfig = { requiresSetup: boolean; }; -export type AgentHealthCheck = { +export type AgentHealthCheckResponse = { seconds_since_last_transition: number; is_tm_healthy: boolean; period: number; diff --git a/frontend/types/Autonolas.ts b/frontend/types/Autonolas.ts index 31e89a449..5fd2a7414 100644 --- a/frontend/types/Autonolas.ts +++ b/frontend/types/Autonolas.ts @@ -8,8 +8,10 @@ const zodBigNumber = z.object({ export const StakingRewardsInfoSchema = z.object({ // mechRequestCount: z.number(), serviceInfo: z.array(z.unknown()), + /* checkpoint period (in seconds). eg. 86400 */ livenessPeriod: zodBigNumber, livenessRatio: zodBigNumber, + /* rewards per second */ rewardsPerSecond: zodBigNumber, isEligibleForRewards: z.boolean(), availableRewardsForEpoch: z.number(), diff --git a/frontend/types/ElectronApi.ts b/frontend/types/ElectronApi.ts index f32a591b9..15bca15c6 100644 --- a/frontend/types/ElectronApi.ts +++ b/frontend/types/ElectronApi.ts @@ -21,6 +21,7 @@ export type ElectronStore = { isProfileWarningDisplayed: boolean; }; [AgentType.AgentsFunCelo]?: AgentSettings; + [AgentType.Optimus]?: AgentSettings; }; export type ElectronTrayIconStatus = diff --git a/frontend/types/Util.ts b/frontend/types/Util.ts index 31ca4bbf5..0528a979d 100644 --- a/frontend/types/Util.ts +++ b/frontend/types/Util.ts @@ -4,6 +4,8 @@ export type Optional = T | undefined; export type Maybe = Nullable>; +export type ValueOf = T[keyof T]; + /** * DeepPartial allows you to make all properties of an object optional. */ diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts index 8f67fb3b6..861741d88 100644 --- a/frontend/utils/middlewareHelpers.ts +++ b/frontend/utils/middlewareHelpers.ts @@ -16,6 +16,8 @@ export const asEvmChainId = (chain?: MiddlewareChain | string): EvmChainId => { return EvmChainId.Base; case MiddlewareChain.MODE: return EvmChainId.Mode; + case MiddlewareChain.OPTIMISM: + return EvmChainId.Optimism; case MiddlewareChain.CELO: return EvmChainId.Celo; } @@ -34,6 +36,8 @@ export const asMiddlewareChain = (chainId?: EvmChainId | number) => { return MiddlewareChain.BASE; case EvmChainId.Mode: return MiddlewareChain.MODE; + case EvmChainId.Optimism: + return MiddlewareChain.OPTIMISM; case EvmChainId.Celo: return MiddlewareChain.CELO; } diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index e58d1959b..c7e36fc56 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -80,22 +80,20 @@ export const updateServiceIfNeeded = async ( service.chain_configs[serviceHomeChain].chain_data.user_params .fund_requirements; const templateFundRequirements = - serviceTemplate.configurations[serviceHomeChain].fund_requirements; + serviceTemplate.configurations[serviceHomeChain]?.fund_requirements; if ( Object.entries(serviceHomeChainFundRequirements).some(([key, item]) => { return ( - templateFundRequirements[key].agent !== item.agent || - templateFundRequirements[key].safe !== item.safe + templateFundRequirements?.[key]?.agent !== item.agent || + templateFundRequirements?.[key]?.safe !== item.safe ); }) ) { // Need to pass all fund requirements from the template // even if some of them were updated partialServiceTemplate.configurations = { - [serviceHomeChain]: { - fund_requirements: templateFundRequirements, - }, + [serviceHomeChain]: { fund_requirements: templateFundRequirements }, }; } diff --git a/frontend/utils/setupMulticall.ts b/frontend/utils/setupMulticall.ts index fdbeb8b74..aa7668328 100644 --- a/frontend/utils/setupMulticall.ts +++ b/frontend/utils/setupMulticall.ts @@ -14,6 +14,7 @@ const addresses: AddressesForAllChainIds = { [EvmChainId.Gnosis]: DEFAULT_MULTICALL_ADDRESS, [EvmChainId.Mode]: DEFAULT_MULTICALL_ADDRESS, [EvmChainId.Celo]: DEFAULT_MULTICALL_ADDRESS, + [EvmChainId.Optimism]: DEFAULT_MULTICALL_ADDRESS, }; /** diff --git a/templates/memeooorr.yaml b/templates/memeooorr.yaml deleted file mode 100644 index 781225ae6..000000000 --- a/templates/memeooorr.yaml +++ /dev/null @@ -1,79 +0,0 @@ -name: "Memeooorr" -description: "Memeooorr @twitter_handle" -hash: bafybeidxfdlaeywhnhafix2yzrnbldk5cybwal53o6mtabnamnxmwtprea -image: https://gateway.autonolas.tech/ipfs/QmQYDGMg8m91QQkTWSSmANs5tZwKrmvUCawXZfXVVWQPcu -service_version: v0.4.2-alpha1 -home_chain: "base" -configurations: - base: - staking_program_id: meme_base_alpha_2 - nft: bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve - rpc: http://localhost:8545 # User provided - threshold: 1 # TODO: Move to service component - use_staking: true # User provided - cost_of_bond: 50000000000000000000 - monthly_gas_estimate: 50000000000000000 # 0.05 - fund_requirements: - agent: 1000000000000000 # 0.001 - safe: 2000000000000000 # 0.002 -env_variables: - BASE_LEDGER_RPC: - name: "Base ledger RPC" - description: "" - value: "" - provision_type: "computed" - CELO_LEDGER_RPC: - name: "Base ledger RPC" - description: "" - value: "" - provision_type: "computed" - TWIKIT_USERNAME: - name: "Twitter username" - description: "" - value: "" - provision_type: "user" - TWIKIT_EMAIL: - name: "Twitter email" - description: "" - value: "" - provision_type: "user" - TWIKIT_PASSWORD: - name: "Twitter password" - description: "" - value: "" - provision_type: "user" - GENAI_API_KEY: - name: "Gemini api key" - description: "" - value: "" - provision_type: "user" - PERSONA: - name: "Persona description" - description: "" - value: "" - provision_type: "user" - FEEDBACK_PERIOD_HOURS: - name: "Feedback period" - description: "" - value: "1" - provision_type: "fixed" - MIN_FEEDBACK_REPLIES: - name: "Minimum feedback replies" - description: "" - value: "10" - provision_type: "fixed" - RESET_PAUSE_DURATION: - name: "Reset pause duration" - description: "" - value: "1800" - provision_type: "fixed" - DB_PATH: - name: "DB path" - description: "" - value: "persistent_data/memeooorr.db" - provision_type: "computed" - TWIKIT_COOKIES_PATH: - name: "Twitter cookies path" - description: "" - value: "persistent_data/twikit_cookies.json" - provision_type: "computed" diff --git a/templates/optimus.yaml b/templates/optimus.yaml deleted file mode 100644 index 0cd81868c..000000000 --- a/templates/optimus.yaml +++ /dev/null @@ -1,43 +0,0 @@ -name: Optimus -hash: bafybeiecjxha2ouqupttgdax7j4xmzfr6icuu55kq5xo2bwhkrl2po5khq -description: Optimus -image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 -service_version: v0.3.15 -home_chain: "optimistic" -configurations: - ethereum: - staking_program_id: optimus_alpha - nft: bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq - agent_id: 14 - threshold: 1 - use_staking: false - use_mech_marketplace: false - cost_of_bond: 1 - monthly_gas_estimate: 1000 #defaulted to 1000 as value unknown for now, needed for testing - fund_requirements: - agent: 1000 - safe: 1000 - optimistic: - staking_program_id: optimus_alpha - nft: bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq - agent_id: 14 - threshold: 1 - use_staking: true - use_mech_marketplace: false - cost_of_bond: 1000 - monthly_gas_estimate: 1000 - fund_requirements: - agent: 1000 - safe: 1000 - base: - staking_program_id: optimus_alpha - nft: bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq - agent_id: 14 - threshold: 1 - use_staking: false - use_mech_marketplace: false - cost_of_bond: 1 - monthly_gas_estimate: 1000 - fund_requirements: - agent: 1000 - safe: 1000 \ No newline at end of file diff --git a/templates/trader.yaml b/templates/trader.yaml deleted file mode 100644 index fd8387c5b..000000000 --- a/templates/trader.yaml +++ /dev/null @@ -1,60 +0,0 @@ -name: "Trader Agent" -description: "A single-agent service (sovereign agent) placing bets on Omen" -hash: bafybeihgmbbjtkrlu62bkm3e4j2ehqipv5huqpifjiyttvjrk4sikwsfzu -image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 -service_version: v0.25.0 -home_chain: "gnosis" -configurations: - gnosis: - staking_program_id: pearl_beta - nft: bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq - rpc: http://localhost:8545 # User provided - threshold: 1 # TODO: Move to service component - use_staking: false # User provided - use_mech_marketplace: false # User provided - cost_of_bond: 10000000000000000 - monthly_gas_estimate: 10000000000000000000 # TODO: Where is this used - fund_requirements: - agent: 100000000000000000 - safe: 5000000000000000000 -env_variables: - GNOSIS_LEDGER_RPC: - name: "Gnosis ledger RPC" - description: "" - value: "" - provision_type: "computed" - STAKING_CONTRACT_ADDRESS: - name: "Staking contract address" - description: "" - value: "" - provision_type: "computed" - MECH_ACTIVITY_CHECKER_CONTRACT: - name: "Mech activity checker contract" - description: "" - value: "" - provision_type: "computed" - MECH_CONTRACT_ADDRESS: - name: "Mech contract address" - description: "" - value: "" - provision_type: "computed" - MECH_REQUEST_PRICE: - name: "Mech request price" - description: "" - value: "" - provision_type: "computed" - USE_MECH_MARKETPLACE: - name: "Use Mech marketplace" - description: "" - value: "" - provision_type: "computed" - REQUESTER_STAKING_INSTANCE_ADDRESS: - name: "Requester staking instance address" - description: "" - value: "" - provision_type: "computed" - PRIORITY_MECH_ADDRESS: - name: "Priority Mech address" - description: "" - value: "" - provision_type: "computed" From f444216880518ed84a1229001680054fe878b741 Mon Sep 17 00:00:00 2001 From: Mohan Date: Fri, 9 May 2025 14:32:42 +0530 Subject: [PATCH 04/44] fix: update feature flags for Optimus agent (#886) --- .../MainPage/sections/KeepAgentRunningSection.tsx | 2 +- frontend/hooks/useFeatureFlag.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx b/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx index 39c7ac30b..ca3e6701b 100644 --- a/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx +++ b/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx @@ -10,7 +10,7 @@ import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; -const cardSectionStyle = { marginBottom: '-1px', marginTop: '24px' }; +const cardSectionStyle = { marginBottom: '-1px' }; export const KeepAgentRunningSection = () => { const { storeState } = useStore(); diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index bf68e7c6c..8d5281c6d 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -74,13 +74,13 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-settings': true, }, [AgentType.Optimus]: { - 'manage-wallet': false, + 'manage-wallet': true, 'withdraw-funds': false, - 'last-transactions': false, - 'rewards-streak': false, - 'staking-contract-section': false, + 'last-transactions': true, + 'rewards-streak': true, + 'staking-contract-section': true, 'low-funds': false, - 'agent-activity': false, + 'agent-activity': true, 'backup-via-safe': false, // temporarily hidden until mode is available on safe https://app.safe.global/new-safe/create 'agent-settings': false, }, From 5bfb8aeab58741863a2dd8b9fcd9542124da9d10 Mon Sep 17 00:00:00 2001 From: Mohan Date: Tue, 13 May 2025 14:07:38 +0530 Subject: [PATCH 05/44] feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- electron/constants/index.js | 1 + electron/main.js | 21 +- electron/public/chains/base-chain.png | Bin 0 -> 2894 bytes electron/public/chains/ethereum-chain.png | Bin 0 -> 2769 bytes electron/public/chains/gnosis-chain.png | Bin 0 -> 3868 bytes electron/public/chains/mode-chain.png | Bin 0 -> 2382 bytes frontend/client/types.ts | 14 +- frontend/components/ExportLogsButton.tsx | 63 ++++ .../MainPage/sections/AddFundsSection.tsx | 156 ++++++-- .../WhatAreStakingContracts.tsx | 39 -- .../components/ManageStakingPage/index.tsx | 43 ++- frontend/components/NumberInput.tsx | 39 ++ .../components/Pages/HelpAndSupportPage.tsx | 74 ++++ .../Pages/HelpAndSupportPage/index.tsx | 127 ------- .../BridgeInProgress/BridgeInProgress.tsx | 254 +++++++++++++ .../BridgeInProgress/useBridgingSteps.ts | 180 +++++++++ .../useMasterSafeCreationAndTransfer.ts | 56 +++ .../BridgeInProgress/useRetryBridge.ts | 24 ++ .../SetupBridgeOnboarding/BridgeOnEvm.tsx | 48 +++ .../SetupBridgeOnboarding.tsx | 94 +++++ .../Create/SetupBridgeOnboarding/types.ts | 1 + .../SetupPage/Create/SetupCreateHeader.tsx | 13 +- .../SetupPage/Create/SetupCreateSafe.tsx | 43 +-- .../SetupPage/Create/SetupEoaFunding.tsx | 261 ++++++++++--- .../SetupPage/Create/SetupPassword.tsx | 5 +- .../components/SetupPage/SetupRestore.tsx | 6 +- frontend/components/SetupPage/index.tsx | 15 +- .../bridge/AddFundsThroughBridge.tsx | 139 +++++++ .../components/bridge/BridgeTransferFlow.tsx | 83 +++++ frontend/components/bridge/BridgingSteps.tsx | 237 ++++++++++++ frontend/components/bridge/DepositAddress.tsx | 42 +++ .../components/bridge/DepositForBridging.tsx | 343 ++++++++++++++++++ .../bridge/EstimatedCompletionTime.tsx | 61 ++++ frontend/components/bridge/TokenDetails.tsx | 95 +++++ frontend/components/bridge/types.ts | 1 + frontend/components/bridge/utils.ts | 216 +++++++++++ frontend/components/styled/CardFlex.tsx | 34 +- frontend/components/styled/CardSection.tsx | 26 +- frontend/components/ui/iconStyles.ts | 6 + frontend/config/tokens.ts | 19 + frontend/constants/address.ts | 5 + frontend/constants/colors.ts | 2 + frontend/constants/intervals.ts | 2 + frontend/constants/react-query-keys.ts | 8 + .../BalancesAndRefillRequirementsProvider.tsx | 44 ++- frontend/context/MasterWalletProvider.tsx | 31 +- frontend/enums/Pages.ts | 1 + frontend/enums/SetupScreen.ts | 3 + frontend/hooks/useBackupSigner.ts | 15 + frontend/hooks/useBridgeRefillRequirements.ts | 37 ++ frontend/hooks/useFeatureFlag.ts | 10 + frontend/hooks/useLogs.ts | 18 +- frontend/hooks/usePageState.ts | 11 +- frontend/pages/index.tsx | 6 + frontend/public/chains/base-chain.png | Bin 0 -> 2894 bytes frontend/public/chains/ethereum-chain.png | Bin 0 -> 2769 bytes frontend/public/chains/gnosis-chain.png | Bin 0 -> 3868 bytes frontend/public/chains/mode-chain.png | Bin 0 -> 2382 bytes frontend/public/olas-icon.png | Bin 0 -> 35622 bytes frontend/service/Bridge.ts | 65 ++++ frontend/service/Wallet.ts | 12 +- frontend/styles/globals.scss | 69 +++- frontend/theme/index.ts | 9 + frontend/types/Bridge.ts | 88 +++++ frontend/types/Wallet.ts | 7 + frontend/utils/address.ts | 11 + frontend/utils/calculations.ts | 9 + frontend/utils/middlewareHelpers.ts | 23 ++ frontend/utils/numberFormatters.ts | 6 +- poetry.lock | 12 +- pyproject.toml | 2 +- 71 files changed, 3016 insertions(+), 369 deletions(-) create mode 100644 electron/public/chains/base-chain.png create mode 100644 electron/public/chains/ethereum-chain.png create mode 100644 electron/public/chains/gnosis-chain.png create mode 100644 electron/public/chains/mode-chain.png create mode 100644 frontend/components/ExportLogsButton.tsx delete mode 100644 frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx create mode 100644 frontend/components/NumberInput.tsx create mode 100644 frontend/components/Pages/HelpAndSupportPage.tsx delete mode 100644 frontend/components/Pages/HelpAndSupportPage/index.tsx create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useBridgingSteps.ts create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useMasterSafeCreationAndTransfer.ts create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useRetryBridge.ts create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/SetupBridgeOnboarding.tsx create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/types.ts create mode 100644 frontend/components/bridge/AddFundsThroughBridge.tsx create mode 100644 frontend/components/bridge/BridgeTransferFlow.tsx create mode 100644 frontend/components/bridge/BridgingSteps.tsx create mode 100644 frontend/components/bridge/DepositAddress.tsx create mode 100644 frontend/components/bridge/DepositForBridging.tsx create mode 100644 frontend/components/bridge/EstimatedCompletionTime.tsx create mode 100644 frontend/components/bridge/TokenDetails.tsx create mode 100644 frontend/components/bridge/types.ts create mode 100644 frontend/components/bridge/utils.ts create mode 100644 frontend/components/ui/iconStyles.ts create mode 100644 frontend/hooks/useBackupSigner.ts create mode 100644 frontend/hooks/useBridgeRefillRequirements.ts create mode 100644 frontend/public/chains/base-chain.png create mode 100644 frontend/public/chains/ethereum-chain.png create mode 100644 frontend/public/chains/gnosis-chain.png create mode 100644 frontend/public/chains/mode-chain.png create mode 100644 frontend/public/olas-icon.png create mode 100644 frontend/service/Bridge.ts create mode 100644 frontend/types/Bridge.ts create mode 100644 frontend/types/Wallet.ts create mode 100644 frontend/utils/address.ts create mode 100644 frontend/utils/calculations.ts diff --git a/electron/constants/index.js b/electron/constants/index.js index 0d3c16db7..ccb2b7d58 100644 --- a/electron/constants/index.js +++ b/electron/constants/index.js @@ -29,6 +29,7 @@ const paths = { electronLogFile: path.join(dotOperateDirectory, 'electron.log'), nextLogFile: path.join(dotOperateDirectory, 'next.log'), osPearlTempDir: path.join(os.tmpdir(), 'pearl'), + bridgeDirectory: path.join(dotOperateDirectory, 'bridge'), }; // Publish options diff --git a/electron/main.js b/electron/main.js index 8418d1430..33e3fb23d 100644 --- a/electron/main.js +++ b/electron/main.js @@ -762,7 +762,9 @@ function sanitizeLogs({ return sanitizedLogsFilePath; } -// EXPORT LOGS +/** + * Exports logs by creating a zip file containing sanitized logs and other relevant data. + */ ipcMain.handle('save-logs', async (_, data) => { const cliLogFiles = fs .readdirSync(paths.dotOperateDirectory) @@ -794,11 +796,12 @@ ipcMain.handle('save-logs', async (_, data) => { fs.writeFileSync(osInfoFilePath, osInfo); // Persistent store - if (data.store) + if (data.store) { sanitizeLogs({ name: 'store.txt', data: JSON.stringify(data.store, null, 2), }); + } // Other debug data: balances, addresses, etc. if (data.debugData) { @@ -824,6 +827,16 @@ ipcMain.handle('save-logs', async (_, data) => { }); } + // Bridge logs + try { + const bridgeLogFilePath = path.join(paths.bridgeDirectory, 'bridge.json'); + if (fs.existsSync(bridgeLogFilePath)) { + sanitizeLogs({ name: 'bridge.json', filePath: bridgeLogFilePath }); + } + } catch (e) { + logger.electron(e); + } + // Agent logs try { fs.readdirSync(paths.servicesDir).forEach((serviceDirName) => { @@ -898,12 +911,12 @@ ipcMain.handle('save-logs', async (_, data) => { } // Remove temporary files - fs.existsSync(paths.osPearlTempDir) && + if (fs.existsSync(paths.osPearlTempDir)) { fs.rmSync(paths.osPearlTempDir, { recursive: true, force: true, }); - + } return result; }); diff --git a/electron/public/chains/base-chain.png b/electron/public/chains/base-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..38b747114cb007e83cd4e652f5ab7ab2e0ad6596 GIT binary patch literal 2894 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 literal 0 HcmV?d00001 diff --git a/electron/public/chains/ethereum-chain.png b/electron/public/chains/ethereum-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..f9685c478d193338893ec9837b3d39b83c00bca5 GIT binary patch literal 2769 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 AYXATM literal 0 HcmV?d00001 diff --git a/frontend/client/types.ts b/frontend/client/types.ts index b104e783e..ec5d3732d 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -142,10 +142,12 @@ export type MiddlewareWalletResponse = { safe_nonce: number; }; +export type MasterSafeBalanceRecord = { + master_safe: { [tokenAddress: Address]: number | string }; +}; + export type AddressBalanceRecord = { - [address: Address]: { - [tokenAddress: Address]: number; - }; + [address: Address]: { [tokenAddress: Address]: number | string }; }; export type BalancesAndFundingRequirements = { @@ -158,10 +160,14 @@ export type BalancesAndFundingRequirements = { * If it not present or is 0, the balance is sufficient. */ refill_requirements: Partial<{ - [chain in MiddlewareChain]: AddressBalanceRecord; + [chain in MiddlewareChain]: AddressBalanceRecord | MasterSafeBalanceRecord; }>; + total_requirements: { + [chain in MiddlewareChain]: AddressBalanceRecord | MasterSafeBalanceRecord; + }; bonded_olas: { [chain in MiddlewareChain]: number; }; + is_refill_required: boolean; allow_start_agent: boolean; }; diff --git a/frontend/components/ExportLogsButton.tsx b/frontend/components/ExportLogsButton.tsx new file mode 100644 index 000000000..dab2eab6e --- /dev/null +++ b/frontend/components/ExportLogsButton.tsx @@ -0,0 +1,63 @@ +import { Button, ButtonProps, message } from 'antd'; +import { useCallback, useEffect, useState } from 'react'; + +import { useElectronApi } from '@/hooks/useElectronApi'; +import { useLogs } from '@/hooks/useLogs'; + +const LogsSavedMessage = ({ onClick }: { onClick: () => void }) => ( + + Logs saved + + +); + +type ExportLogsButtonProps = { size?: ButtonProps['size'] }; + +export const ExportLogsButton = ({ size }: ExportLogsButtonProps) => { + const { openPath, saveLogs } = useElectronApi(); + const logs = useLogs(); + + const [isLoading, setIsLoading] = useState(false); + const [canSaveLogs, setCanSaveLogs] = useState(false); + + const onSaveLogs = useCallback(() => setCanSaveLogs(true), []); + + useEffect(() => { + if (isLoading) return; + if (!logs) return; + if (!canSaveLogs) return; + + setIsLoading(true); + saveLogs?.(logs) + .then((result) => { + if (result.success) { + message.success({ + content: ( + openPath?.(result.dirPath)} /> + ), + duration: 10, + }); + } else { + message.error('Save logs failed or cancelled'); + } + }) + .finally(() => { + setIsLoading(false); + setCanSaveLogs(false); + }); + }, [canSaveLogs, isLoading, logs, openPath, saveLogs]); + + return ( + + ); +}; diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index 993965c53..178a58083 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -1,12 +1,17 @@ import { CopyOutlined } from '@ant-design/icons'; -import { Button, Flex, message, Tooltip, Typography } from 'antd'; +import { Button, Flex, message, Segmented, Tooltip, Typography } from 'antd'; import Link from 'next/link'; import { forwardRef, useCallback, useMemo, useRef, useState } from 'react'; import { CustomAlert } from '@/components/Alert'; +import { SendFundAction } from '@/components/bridge/types'; import { CHAIN_CONFIG } from '@/config/chains'; import { NA, UNICODE_SYMBOLS } from '@/constants/symbols'; import { SWAP_URL_BY_EVM_CHAIN } from '@/constants/urls'; +import { EvmChainName } from '@/enums/Chain'; +import { Pages } from '@/enums/Pages'; +import { useFeatureFlag } from '@/hooks/useFeatureFlag'; +import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { copyToClipboard } from '@/utils/copyToClipboard'; @@ -17,39 +22,10 @@ import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; -export const AddFundsSection = () => { - const fundSectionRef = useRef(null); - const [isAddFundsVisible, setIsAddFundsVisible] = useState(false); - - const addFunds = useCallback(async () => { - setIsAddFundsVisible(true); - - await delayInSeconds(0.1); - fundSectionRef?.current?.scrollIntoView({ behavior: 'smooth' }); - }, []); - const closeAddFunds = useCallback(() => setIsAddFundsVisible(false), []); - - return ( - <> - - - - - {isAddFundsVisible && } - - ); -}; - const AddFundsWarningAlertSection = () => { const { selectedAgentConfig } = useServices(); const { evmHomeChainId: homeChainId } = selectedAgentConfig; + return ( { ); }; +type AddFundsAddressSectionProps = { + fundingAddress?: string; + truncatedFundingAddress?: string; + handleCopy: () => void; +}; + const AddFundsAddressSection = ({ fundingAddress, truncatedFundingAddress, handleCopy, -}: { - fundingAddress?: string; - truncatedFundingAddress?: string; - handleCopy: () => void; -}) => ( +}: AddFundsAddressSectionProps) => ( ((_, ref) => { ); }); OpenAddFundsSection.displayName = 'OpenAddFundsSection'; + +const AddFundsBy = forwardRef((_, ref) => { + const [isBridgeOnboardingEnabled, isBridgeAddFundsEnabled] = useFeatureFlag([ + 'bridge-onboarding', + 'bridge-add-funds', + ]); + const { selectedAgentConfig } = useServices(); + const { goto } = usePageState(); + + const [fundType, setFundType] = useState('transfer'); + + const { evmHomeChainId: homeChainId } = selectedAgentConfig; + const currentFundingRequirements = CHAIN_CONFIG[homeChainId]; + + const bridgeFundsBtn = useMemo( + () => ( + + ), + [goto, isBridgeAddFundsEnabled], + ); + + return ( + <> + {isBridgeOnboardingEnabled && ( + + + options={[ + { + label: `Send on ${currentFundingRequirements.name}`, + value: 'transfer', + }, + { label: 'Bridge from Ethereum', value: 'bridge' }, + ]} + onChange={setFundType} + value={fundType} + block + className="w-full" + /> + + )} + + {fundType === 'bridge' ? ( + + + Bridge funds from Ethereum directly to your Pearl Safe on{' '} + {EvmChainName[homeChainId]} chain. + + {isBridgeAddFundsEnabled ? ( + bridgeFundsBtn + ) : ( + {bridgeFundsBtn} + )} + + ) : ( + + )} + + ); +}); +AddFundsBy.displayName = 'AddFundsBy'; + +export const AddFundsSection = () => { + const fundSectionRef = useRef(null); + const [isAddFundsVisible, setIsAddFundsVisible] = useState(false); + + const addFunds = useCallback(async () => { + setIsAddFundsVisible(true); + + await delayInSeconds(0.1); + fundSectionRef?.current?.scrollIntoView({ behavior: 'smooth' }); + }, []); + const closeAddFunds = useCallback(() => setIsAddFundsVisible(false), []); + + return ( + <> + + + + + {isAddFundsVisible && } + + ); +}; diff --git a/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx b/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx deleted file mode 100644 index fa849568d..000000000 --- a/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Collapse, Flex, Typography } from 'antd'; - -import { CardSection } from '../styled/CardSection'; - -const { Text } = Typography; - -const collapseItems = [ - { - key: 1, - label: What are staking contracts?, - children: ( - - - When your agent goes to work, it participates in staking contracts. - - - Staking contracts define what the agent needs to do, how much OLAS - needs to be staked, etc., to be eligible for rewards. - - - Your agent can only participate in one staking contract at a time. - - - ), - }, -]; - -export const WhatAreStakingContractsSection = () => { - return ( - - - - ); -}; diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index ce4e70df1..fd7a173b4 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,4 +1,4 @@ -import { Card } from 'antd'; +import { Card, Collapse, Flex, Typography } from 'antd'; import { useMemo } from 'react'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; @@ -10,7 +10,42 @@ import { CardTitle } from '../Card/CardTitle'; import { GoToMainPageButton } from '../Pages/GoToMainPageButton'; import { CardSection } from '../styled/CardSection'; import { StakingContractSection } from './StakingContractSection'; -import { WhatAreStakingContractsSection } from './WhatAreStakingContracts'; + +const { Text } = Typography; + +const collapseItems = [ + { + key: 1, + label: What are staking contracts?, + children: ( + + + When your agent goes to work, it participates in staking contracts. + + + Staking contracts define what the agent needs to do, how much OLAS + needs to be staked, etc., to be eligible for rewards. + + + Your agent can only participate in one staking contract at a time. + + + ), + }, +]; + +const WhatAreStakingContractsSection = () => { + return ( + + + + ); +}; export const ManageStakingPage = () => { const { selectedAgentConfig } = useServices(); @@ -98,9 +133,7 @@ export const ManageStakingPage = () => { )} ) => { + const isCopy = (e.ctrlKey || e.metaKey) && e.key === 'c'; + const isPaste = (e.ctrlKey || e.metaKey) && e.key === 'v'; + const isCut = (e.ctrlKey || e.metaKey) && e.key === 'x'; + const isSelectAll = (e.ctrlKey || e.metaKey) && e.key === 'a'; + + if ( + !/[0-9]/.test(e.key) && + e.key !== 'Backspace' && + e.key !== 'Delete' && + e.key !== 'ArrowLeft' && + e.key !== 'ArrowRight' && + e.key !== 'Tab' && + e.key !== '.' && + !isCopy && + !isPaste && + !isCut && + !isSelectAll + ) { + e.preventDefault(); + } + + // Prevent more than one decimal point + const value = e.currentTarget.value; + if (e.key === '.' && value.includes('.')) { + e.preventDefault(); + } +}; + +export const NumberInput = ({ value, ...rest }: InputNumberProps) => ( + + {...rest} + value={typeof value === 'string' ? parseFloat(value) : value} + formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} + onKeyDown={allowOnlyNumbers} + /> +); diff --git a/frontend/components/Pages/HelpAndSupportPage.tsx b/frontend/components/Pages/HelpAndSupportPage.tsx new file mode 100644 index 000000000..d3fca067f --- /dev/null +++ b/frontend/components/Pages/HelpAndSupportPage.tsx @@ -0,0 +1,74 @@ +import { QuestionCircleOutlined } from '@ant-design/icons'; +import { Card, Flex, Typography } from 'antd'; + +import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { + FAQ_URL, + SUPPORT_URL, + TERMS_AND_CONDITIONS_URL, +} from '@/constants/urls'; + +import { CardTitle } from '../Card/CardTitle'; +import { ExportLogsButton } from '../ExportLogsButton'; +import { CardSection } from '../styled/CardSection'; +import { GoToMainPageButton } from './GoToMainPageButton'; + +const { Title, Paragraph } = Typography; + +const SettingsTitle = () => ( + + + Help & support + + } + /> +); + +export const HelpAndSupport = () => { + return ( + } + bordered={false} + styles={{ + body: { + paddingTop: 0, + paddingBottom: 0, + }, + }} + extra={} + > + + + Frequently asked questions + + + Read FAQ {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + Terms and Conditions {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + + + + Ask for help + + + Get your questions answered by the community. + + + Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + + + + Export logs for troubleshooting + + + + + ); +}; diff --git a/frontend/components/Pages/HelpAndSupportPage/index.tsx b/frontend/components/Pages/HelpAndSupportPage/index.tsx deleted file mode 100644 index 868619187..000000000 --- a/frontend/components/Pages/HelpAndSupportPage/index.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { QuestionCircleOutlined } from '@ant-design/icons'; -import { Button, Card, Flex, message, Typography } from 'antd'; -import { useCallback, useEffect, useState } from 'react'; - -import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { - FAQ_URL, - SUPPORT_URL, - TERMS_AND_CONDITIONS_URL, -} from '@/constants/urls'; -import { useElectronApi } from '@/hooks/useElectronApi'; -import { useLogs } from '@/hooks/useLogs'; - -import { CardTitle } from '../../Card/CardTitle'; -import { CardSection } from '../../styled/CardSection'; -import { GoToMainPageButton } from '../GoToMainPageButton'; - -const { Title, Paragraph } = Typography; - -const SettingsTitle = () => ( - - - Help & support - - } - /> -); - -const LogsSavedMessage = ({ onClick }: { onClick: () => void }) => { - return ( - - Logs saved - - - ); -}; - -export const HelpAndSupport = () => { - const { openPath, saveLogs } = useElectronApi(); - - const logs = useLogs(); - - const [isLoading, setIsLoading] = useState(false); - const [canSaveLogs, setCanSaveLogs] = useState(false); - - const onSaveLogs = useCallback(() => setCanSaveLogs(true), []); - - useEffect(() => { - if (canSaveLogs && logs && !isLoading) { - setIsLoading(true); - saveLogs?.(logs) - .then((result) => { - if (result.success) { - message.success({ - content: ( - openPath?.(result.dirPath)} /> - ), - duration: 10, - }); - } else { - message.error('Save logs failed or cancelled'); - } - }) - .finally(() => { - setIsLoading(false); - setCanSaveLogs(false); - }); - } - }, [canSaveLogs, isLoading, logs, openPath, saveLogs]); - - return ( - } - bordered={false} - styles={{ - body: { - paddingTop: 0, - paddingBottom: 0, - }, - }} - extra={} - > - - - Frequently asked questions - - - Read FAQ {UNICODE_SYMBOLS.EXTERNAL_LINK} - - - Terms and Conditions {UNICODE_SYMBOLS.EXTERNAL_LINK} - - - - - - Ask for help - - - Get your questions answered by the community. - - - Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} - - - - - - Export logs for troubleshooting - - - - - ); -}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx new file mode 100644 index 000000000..3780b572a --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx @@ -0,0 +1,254 @@ +import { Typography } from 'antd'; +import { useCallback, useEffect, useMemo } from 'react'; + +import { CustomAlert } from '@/components/Alert'; +import { BridgeTransferFlow } from '@/components/bridge/BridgeTransferFlow'; +import { BridgingSteps, StepEvent } from '@/components/bridge/BridgingSteps'; +import { CardFlex } from '@/components/styled/CardFlex'; +import { Pages } from '@/enums/Pages'; +import { usePageState } from '@/hooks/usePageState'; +import { BridgingStepStatus, CrossChainTransferDetails } from '@/types/Bridge'; +import { Nullable } from '@/types/Util'; + +import { SetupCreateHeader } from '../../SetupCreateHeader'; +import { BridgeRetryOutcome } from '../types'; +import { useBridgingSteps } from './useBridgingSteps'; +import { useMasterSafeCreationAndTransfer } from './useMasterSafeCreationAndTransfer'; +import { useRetryBridge } from './useRetryBridge'; + +const { Text, Title } = Typography; + +const KeepAppOpenAlert = () => ( + + Keep the app open until bridging is complete. + + } + /> +); + +const Header = () => ( + <> + + + + Bridging in progress + + + + +); + +type BridgeInProgressProps = { + quoteId: string; + bridgeRetryOutcome: Nullable; + onBridgeRetryOutcome: (outcome: Nullable) => void; +} & CrossChainTransferDetails; + +/** + * Bridge in progress screen. + */ +export const BridgeInProgress = ({ + quoteId, + fromChain, + toChain, + transfers, + bridgeRetryOutcome, + onBridgeRetryOutcome, +}: BridgeInProgressProps) => { + const { goto } = usePageState(); + const symbols = transfers.map((transfer) => transfer.toSymbol); + + const refetchBridgeExecute = useRetryBridge(); + + const { isBridging, isBridgingFailed, isBridgingCompleted, bridgeStatus } = + useBridgingSteps(quoteId, symbols); + const { + isPending: isLoadingMasterSafeCreation, + isError: isErrorMasterSafeCreation, + data: masterSafeDetails, + mutateAsync: createMasterSafe, + } = useMasterSafeCreationAndTransfer(symbols); + + const isSafeCreated = masterSafeDetails?.isSafeCreated; + const isTransferCompleted = + masterSafeDetails?.masterSafeTransferStatus === 'FINISHED'; + + // Create master safe after the bridging is completed + // and if the master safe is not created yet. + useEffect(() => { + // if refill is required, do not create master safe. + if (bridgeRetryOutcome === 'NEED_REFILL') return; + + // if bridging is in progress or if it has failed, do not create master safe. + if (isBridging) return; + if (isBridgingFailed) return; + if (!isBridgingCompleted) return; + + // if master safe creation is in progress or if it has failed, do not create master safe. + if (isLoadingMasterSafeCreation) return; + if (isErrorMasterSafeCreation) return; + if (masterSafeDetails?.isSafeCreated) return; + + createMasterSafe(); + }, [ + bridgeRetryOutcome, + isBridgingCompleted, + isBridging, + isBridgingFailed, + isLoadingMasterSafeCreation, + masterSafeDetails, + isErrorMasterSafeCreation, + createMasterSafe, + ]); + + // Redirect to main page if all 3 steps are completed + useEffect(() => { + // if retry outcome is not null, do not redirect. + if (bridgeRetryOutcome === 'NEED_REFILL') return; + + // if bridging is in progress or if it has failed, do not redirect. + if (isBridging) return; + if (isBridgingFailed) return; + if (!isBridgingCompleted) return; + + // if master safe creation is in progress or if it has failed, do not redirect. + if (isLoadingMasterSafeCreation) return; + if (!isSafeCreated) return; + if (!isTransferCompleted) return; + + // wait for 3 seconds before redirecting to main page. + const timeoutId = setTimeout(() => goto(Pages.Main), 3000); + return () => clearTimeout(timeoutId); + }, [ + bridgeRetryOutcome, + isBridging, + isBridgingFailed, + isBridgingCompleted, + isLoadingMasterSafeCreation, + isSafeCreated, + isTransferCompleted, + goto, + ]); + + const onBridgeFailRetry = useCallback(() => { + refetchBridgeExecute((e: Nullable) => + onBridgeRetryOutcome(e), + ); + }, [refetchBridgeExecute, onBridgeRetryOutcome]); + + const bridgeDetails = useMemo(() => { + const currentBridgeStatus: BridgingStepStatus = (() => { + if (bridgeRetryOutcome === 'NEED_REFILL') return 'wait'; + if (isBridgingFailed) return 'error'; + if (isBridging) return 'process'; + if (!bridgeStatus) return 'wait'; + if (isBridgingCompleted) return 'finish'; + + return 'process'; + })(); + + return { + status: currentBridgeStatus, + subSteps: (bridgeStatus || []).map((step) => ({ + ...step, + onRetry: onBridgeFailRetry, + onRetryProps: { isLoading: currentBridgeStatus === 'process' }, + })) satisfies StepEvent[], + }; + }, [ + bridgeRetryOutcome, + isBridging, + isBridgingFailed, + isBridgingCompleted, + bridgeStatus, + onBridgeFailRetry, + ]); + + const masterSafeCreationDetails = useMemo(() => { + const currentMasterSafeCreationStatus: BridgingStepStatus = (() => { + if (bridgeRetryOutcome === 'NEED_REFILL') return 'wait'; + if (isBridging || !isBridgingCompleted) return 'wait'; + if (isErrorMasterSafeCreation) return 'error'; + if (isLoadingMasterSafeCreation) return 'process'; + if (isSafeCreated) return 'finish'; + return 'process'; + })(); + + return { + status: currentMasterSafeCreationStatus, + subSteps: [ + { + txnLink: null, // BE to be updated to return the txn link + onRetry: createMasterSafe, + onRetryProps: { + isLoading: currentMasterSafeCreationStatus === 'process', + }, + }, + ] satisfies StepEvent[], + }; + }, [ + bridgeRetryOutcome, + isBridging, + isBridgingCompleted, + isSafeCreated, + isLoadingMasterSafeCreation, + isErrorMasterSafeCreation, + createMasterSafe, + ]); + + const masterSafeTransferDetails = useMemo(() => { + const currentMasterSafeStatus: BridgingStepStatus = (() => { + if (bridgeRetryOutcome === 'NEED_REFILL') return 'wait'; + if (isErrorMasterSafeCreation) return 'error'; + if (isBridging || !isBridgingCompleted || !isSafeCreated) return 'wait'; + return isTransferCompleted ? 'finish' : 'wait'; + })(); + + return { + status: currentMasterSafeStatus, + subSteps: (masterSafeDetails?.transfers || []).map((transfer) => ({ + ...transfer, + onRetry: createMasterSafe, + onRetryProps: { + isLoading: masterSafeCreationDetails.status === 'process', + }, + })) satisfies StepEvent[], + }; + }, [ + bridgeRetryOutcome, + isErrorMasterSafeCreation, + isSafeCreated, + isBridging, + isBridgingCompleted, + isTransferCompleted, + masterSafeCreationDetails, + masterSafeDetails?.transfers, + createMasterSafe, + ]); + + return ( + <> +
      + + + {!!bridgeDetails && ( + + )} + + + ); +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useBridgingSteps.ts b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useBridgingSteps.ts new file mode 100644 index 000000000..ae32a5e7c --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useBridgingSteps.ts @@ -0,0 +1,180 @@ +import { useQuery } from '@tanstack/react-query'; +import { useMemo } from 'react'; + +import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { TokenSymbol } from '@/enums/Token'; +import { useOnlineStatusContext } from '@/hooks/useOnlineStatus'; +import { BridgeService } from '@/service/Bridge'; +import { BridgeStatusResponse, BridgingStepStatus } from '@/types/Bridge'; + +const isBridgingFailedFn = ( + requests: BridgeStatusResponse['bridge_request_status'] = [], +) => + requests + ? requests.some((step) => step.status === 'EXECUTION_FAILED') + : false; + +const isBridgingCompletedFn = ( + requests: BridgeStatusResponse['bridge_request_status'] = [], +) => requests.every((step) => step.status === 'EXECUTION_DONE'); + +const getBridgeStats = ({ + stats, + tokenSymbols, +}: { + hasAnyBridgeFailed?: boolean; + tokenSymbols: TokenSymbol[]; + stats: BridgeStatusResponse['bridge_request_status']; +}) => + stats.map((step, index) => { + const stepStatus: BridgingStepStatus = (() => { + if (step.status === 'EXECUTION_DONE') return 'finish'; + if (step.status === 'EXECUTION_FAILED') return 'error'; + if (step.status === 'EXECUTION_PENDING') return 'process'; + return 'process'; + })(); + + return { + symbol: tokenSymbols[index], + status: stepStatus, + txnLink: step.explorer_link, + }; + }); + +// hook to fetch bridging steps (step 1) +export const useBridgingSteps = ( + quoteId: string, + tokenSymbols: TokenSymbol[], +) => { + const { isOnline } = useOnlineStatusContext(); + + // `/execute` bridge API should be called first before fetching the status. + const { + isLoading: isBridgeExecuteLoading, + isFetching: isBridgeExecuteFetching, + isError: isBridgeExecuteError, + data: bridgeExecuteData, + } = useQuery({ + queryKey: REACT_QUERY_KEYS.BRIDGE_EXECUTE_KEY(quoteId), + queryFn: async () => { + try { + return await BridgeService.executeBridge(quoteId); + } catch (error) { + console.error('Error executing bridge', error); + throw error; + } + }, + enabled: !!quoteId && isOnline, + retry: false, + refetchOnWindowFocus: false, + refetchInterval: false, + }); + + const isBridgingExecuteFailed = isBridgingFailedFn( + bridgeExecuteData?.bridge_request_status, + ); + const isBridgingExecuteCompleted = isBridgingCompletedFn( + bridgeExecuteData?.bridge_request_status, + ); + + const { + isLoading: isBridgeStatusLoading, + isError: isBridgeStatusError, + data: bridgeStatusData, + } = useQuery({ + queryKey: REACT_QUERY_KEYS.BRIDGE_STATUS_BY_QUOTE_ID_KEY(quoteId), + queryFn: async ({ signal }) => { + try { + return await BridgeService.getBridgeStatus(quoteId, signal); + } catch (error) { + console.error('Error fetching bridge status', error); + throw error; + } + }, + // fetch by interval until the status is FINISHED + refetchInterval: + isBridgingExecuteFailed || isBridgingExecuteCompleted + ? false + : FIVE_SECONDS_INTERVAL, + enabled: !!quoteId && isOnline && !!bridgeExecuteData, + retry: false, + refetchOnWindowFocus: false, + }); + + const isBridging = useMemo(() => { + if (isBridgeExecuteLoading) return true; + if (isBridgeStatusLoading) return true; + return false; + }, [isBridgeExecuteLoading, isBridgeStatusLoading]); + + const isBridgingCompleted = useMemo(() => { + // If the bridge execute itself has EXECUTION_DONE, we can consider the bridging as completed. + // and we don't need to check the status. + if (isBridgingExecuteCompleted) return true; + + return isBridgingCompletedFn(bridgeStatusData?.bridge_request_status); + }, [isBridgingExecuteCompleted, bridgeStatusData]); + + const hasAnyBridgeFailed = useMemo( + () => + isBridgingExecuteFailed || + isBridgingFailedFn(bridgeStatusData?.bridge_request_status), + [isBridgingExecuteFailed, bridgeStatusData], + ); + + // if the bridge status is 'EXECUTION_FAILED' or 'EXECUTION_PENDING' + // and the API has error, we can consider the bridging as failed. + const isBridgingFailed = useMemo(() => { + if (isBridgeExecuteError) return true; + if (isBridgeStatusError) return true; + if (hasAnyBridgeFailed) return true; + return false; + }, [isBridgeExecuteError, isBridgeStatusError, hasAnyBridgeFailed]); + + const executeBridgeSteps = useMemo(() => { + if (isBridgeExecuteLoading) return; + if (isBridgeExecuteFetching) return; + if (isBridgeExecuteError) return; + if (!bridgeExecuteData) return; + + return getBridgeStats({ + stats: bridgeExecuteData.bridge_request_status, + tokenSymbols, + }); + }, [ + isBridgeExecuteLoading, + isBridgeExecuteFetching, + isBridgeExecuteError, + bridgeExecuteData, + tokenSymbols, + ]); + + const statusBridgeSteps = useMemo(() => { + if (isBridgeStatusLoading) return; + if (isBridgeStatusError) return; + if (!bridgeStatusData) return; + + return getBridgeStats({ + stats: bridgeStatusData.bridge_request_status, + tokenSymbols, + }); + }, [ + isBridgeStatusLoading, + isBridgeStatusError, + bridgeStatusData, + tokenSymbols, + ]); + + const bridgeStatus = useMemo(() => { + if (isBridgingExecuteCompleted) return executeBridgeSteps; + return statusBridgeSteps; + }, [isBridgingExecuteCompleted, executeBridgeSteps, statusBridgeSteps]); + + return { + isBridging, + isBridgingFailed, + isBridgingCompleted, + bridgeStatus, + }; +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useMasterSafeCreationAndTransfer.ts b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useMasterSafeCreationAndTransfer.ts new file mode 100644 index 000000000..aabb858f1 --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useMasterSafeCreationAndTransfer.ts @@ -0,0 +1,56 @@ +import { useMutation } from '@tanstack/react-query'; + +import { TokenSymbol } from '@/enums/Token'; +import { useBackupSigner } from '@/hooks/useBackupSigner'; +import { useElectronApi } from '@/hooks/useElectronApi'; +import { useServices } from '@/hooks/useServices'; +import { WalletService } from '@/service/Wallet'; +import { BridgingStepStatus } from '@/types/Bridge'; + +/** + * Hook to create master safe and transfer funds (step 2 and 3) + */ +export const useMasterSafeCreationAndTransfer = ( + tokenSymbols: TokenSymbol[], +) => { + const electronApi = useElectronApi(); + const backupSignerAddress = useBackupSigner(); + const { selectedAgentType, selectedAgentConfig } = useServices(); + + const chain = selectedAgentConfig.middlewareHomeChainId; + + return useMutation({ + mutationFn: async () => { + try { + const response = await WalletService.createSafe( + chain, + backupSignerAddress, + true, // transfer excess assets ("true" for bridge onboarding) + ); + + return { + isSafeCreated: true, + txnLink: response.create_tx, + + // NOTE: Currently, both creation and transfer are handled in the same API call. + // Hence, the response contains the transfer status as well. + masterSafeTransferStatus: 'FINISHED', + transfers: tokenSymbols.map((symbol) => ({ + symbol, + status: 'finish' as BridgingStepStatus, + txnLink: null, // TODO: to integrate + })), + }; + } catch (error) { + console.error('Safe creation failed:', error); + throw error; + } + }, + onSuccess: () => { + // Since the master safe is created and the transfer is completed, + // we can update the store to indicate that the agent is initially funded. + // TODO: logic to be moved to BE in the future. + electronApi.store?.set?.(`${selectedAgentType}.isInitialFunded`, true); + }, + }); +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useRetryBridge.ts b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useRetryBridge.ts new file mode 100644 index 000000000..9a8722bed --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useRetryBridge.ts @@ -0,0 +1,24 @@ +import { useCallback } from 'react'; + +import { useBalanceAndRefillRequirementsContext } from '@/hooks/useBalanceAndRefillRequirementsContext'; +import { Nullable } from '@/types/Util'; + +import { BridgeRetryOutcome } from '../types'; + +/*** + * Hook to handle retrying the bridge step + * If refill is required, it will navigate to the refill page + */ +export const useRetryBridge = () => { + const { refetch } = useBalanceAndRefillRequirementsContext(); + + return useCallback( + async (onRetryOutcome: (e: Nullable) => void) => { + if (!refetch) return; + + const { data } = await refetch(); + onRetryOutcome(data?.is_refill_required ? 'NEED_REFILL' : null); + }, + [refetch], + ); +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx new file mode 100644 index 000000000..a80e61cee --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx @@ -0,0 +1,48 @@ +import { Typography } from 'antd'; + +import { DepositForBridging } from '@/components/bridge/DepositForBridging'; +import { CardFlex } from '@/components/styled/CardFlex'; +import { CardSection } from '@/components/styled/CardSection'; +import { SetupScreen } from '@/enums/SetupScreen'; +import { CrossChainTransferDetails } from '@/types/Bridge'; + +import { SetupCreateHeader } from '../SetupCreateHeader'; + +const { Text, Title } = Typography; + +const FROM_CHAIN_NAME = 'Ethereum'; + +type BridgeOnEvmProps = { + onNext: () => void; + updateQuoteId: (quoteId: string) => void; + updateCrossChainTransferDetails: (details: CrossChainTransferDetails) => void; +}; + +export const BridgeOnEvm = ({ + onNext, + updateQuoteId, + updateCrossChainTransferDetails, +}: BridgeOnEvmProps) => { + return ( + + + + + + Bridge from {FROM_CHAIN_NAME} + + + The bridged amount covers all funds required to create your account + and run your agent, including fees. No further funds will be needed. + + + + + + ); +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/SetupBridgeOnboarding.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/SetupBridgeOnboarding.tsx new file mode 100644 index 000000000..467e04bf8 --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/SetupBridgeOnboarding.tsx @@ -0,0 +1,94 @@ +import { useCallback, useEffect, useState } from 'react'; + +import { Pages } from '@/enums/Pages'; +import { usePageState } from '@/hooks/usePageState'; +import { CrossChainTransferDetails } from '@/types/Bridge'; +import { Nullable } from '@/types/Util'; + +import { BridgeInProgress } from './BridgeInProgress/BridgeInProgress'; +import { BridgeOnEvm } from './BridgeOnEvm'; +import { BridgeRetryOutcome } from './types'; + +const QUOTE_ID_ERROR = 'Quote ID is required for in progress state'; +const TRANSFER_AMOUNTS_ERROR = + 'Transfer and receiving amounts are required for in progress state'; + +type BridgeState = 'depositing' | 'in_progress'; + +export const SetupBridgeOnboarding = () => { + const { goto } = usePageState(); + const [bridgeState, setBridgeState] = useState('depositing'); + const [quoteId, setQuoteId] = useState>(null); + const [transferAndReceivingAmounts, setTransferAndReceivingAmounts] = + useState>(null); + const [bridgeRetryOutcome, setBridgeRetryOutcome] = + useState>(null); + + const updateQuoteId = useCallback( + (quoteId: string) => setQuoteId(quoteId), + [setQuoteId], + ); + + const updateCrossChainTransferDetails = useCallback( + (details: CrossChainTransferDetails) => + setTransferAndReceivingAmounts(details), + [setTransferAndReceivingAmounts], + ); + + // If retry outcome is set, we need to update the bridge state + useEffect(() => { + if (!bridgeRetryOutcome) return; + + switch (bridgeRetryOutcome) { + case 'NEED_REFILL': { + setBridgeState('depositing'); + setQuoteId(null); + setTransferAndReceivingAmounts(null); + setBridgeRetryOutcome(null); + break; + } + default: + break; + } + }, [bridgeRetryOutcome]); + + const handleNextStep = useCallback(() => { + switch (bridgeState) { + case 'depositing': + setBridgeState('in_progress'); + break; + case 'in_progress': + goto(Pages.Main); + break; + default: + throw new Error('Invalid bridge state'); + } + }, [bridgeState, goto]); + + switch (bridgeState) { + case 'depositing': + return ( + + ); + case 'in_progress': { + if (!quoteId) throw new Error(QUOTE_ID_ERROR); + if (!transferAndReceivingAmounts) throw new Error(TRANSFER_AMOUNTS_ERROR); + return ( + ) => + setBridgeRetryOutcome(e) + } + /> + ); + } + default: + throw new Error('Invalid bridge state!'); + } +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/types.ts b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/types.ts new file mode 100644 index 000000000..605282d2b --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/types.ts @@ -0,0 +1 @@ +export type BridgeRetryOutcome = 'NEED_REFILL'; diff --git a/frontend/components/SetupPage/Create/SetupCreateHeader.tsx b/frontend/components/SetupPage/Create/SetupCreateHeader.tsx index e41af3bf1..97c171cfa 100644 --- a/frontend/components/SetupPage/Create/SetupCreateHeader.tsx +++ b/frontend/components/SetupPage/Create/SetupCreateHeader.tsx @@ -23,12 +23,13 @@ export const SetupCreateHeader = ({ prev }: SetupCreateHeaderProps) => { return ( - + + )} + ); }; diff --git a/frontend/components/SetupPage/Create/SetupPassword.tsx b/frontend/components/SetupPage/Create/SetupPassword.tsx index 44c90af03..c906ef081 100644 --- a/frontend/components/SetupPage/Create/SetupPassword.tsx +++ b/frontend/components/SetupPage/Create/SetupPassword.tsx @@ -2,6 +2,7 @@ import { Button, Checkbox, Form, Input, message, Typography } from 'antd'; import { useState } from 'react'; import { SetupScreen } from '@/enums/SetupScreen'; +import { usePageState } from '@/hooks/usePageState'; import { useSetup } from '@/hooks/useSetup'; import { AccountService } from '@/service/Account'; import { WalletService } from '@/service/Wallet'; @@ -13,6 +14,7 @@ const { Title, Text } = Typography; export const SetupPassword = () => { const { goto, setMnemonic } = useSetup(); + const { setUserLoggedIn } = usePageState(); const [form] = Form.useForm<{ password: string; terms: boolean }>(); const [isLoading, setIsLoading] = useState(false); @@ -28,6 +30,7 @@ export const SetupPassword = () => { .then(({ mnemonic }: { mnemonic: string[] }) => { setMnemonic(mnemonic); goto(SetupScreen.SetupSeedPhrase); + setUserLoggedIn(); }) .catch((e) => { console.error(e); @@ -37,7 +40,7 @@ export const SetupPassword = () => { }; return ( - + Create password Come up with a strong password. diff --git a/frontend/components/SetupPage/SetupRestore.tsx b/frontend/components/SetupPage/SetupRestore.tsx index 996fab59e..18be04f15 100644 --- a/frontend/components/SetupPage/SetupRestore.tsx +++ b/frontend/components/SetupPage/SetupRestore.tsx @@ -32,7 +32,7 @@ export const SetupRestoreMain = () => { } > - + You can recover the Pearl account access by providing the seed phrase you received when setting up your account. @@ -53,8 +53,9 @@ export const SetupRestoreMain = () => { If you don’t have the seed phrase but added a backup wallet to your @@ -190,6 +191,7 @@ export const SetupRestoreViaBackup = () => { } + $noBorder > diff --git a/frontend/components/SetupPage/index.tsx b/frontend/components/SetupPage/index.tsx index 515e28184..908a934ba 100644 --- a/frontend/components/SetupPage/index.tsx +++ b/frontend/components/SetupPage/index.tsx @@ -1,11 +1,14 @@ +import { Typography } from 'antd'; import { useContext, useMemo } from 'react'; import { SetupContext } from '@/context/SetupProvider'; import { SetupScreen } from '@/enums/SetupScreen'; import { AgentSelection } from '../AgentSelection'; +import { CardFlex } from '../styled/CardFlex'; import { AgentIntroduction } from './AgentIntroduction/AgentIntroduction'; import { SetupBackupSigner } from './Create/SetupBackupSigner'; +import { SetupBridgeOnboarding } from './Create/SetupBridgeOnboarding/SetupBridgeOnboarding'; import { SetupCreateSafe } from './Create/SetupCreateSafe'; import { SetupEoaFunding } from './Create/SetupEoaFunding'; import { SetupPassword } from './Create/SetupPassword'; @@ -20,8 +23,14 @@ import { import { SetupWelcome } from './SetupWelcome'; import { SetupYourAgent } from './SetupYourAgent/SetupYourAgent'; +const { Title } = Typography; + const UnexpectedError = () => ( -
      Something went wrong!
      + + + Something went wrong! + + ); export const Setup = () => { @@ -54,6 +63,10 @@ export const Setup = () => { case SetupScreen.SetupYourAgent: return ; + // Bridge account + case SetupScreen.SetupBridgeOnboardingScreen: + return ; + // Restore account case SetupScreen.Restore: return ; diff --git a/frontend/components/bridge/AddFundsThroughBridge.tsx b/frontend/components/bridge/AddFundsThroughBridge.tsx new file mode 100644 index 000000000..06224852b --- /dev/null +++ b/frontend/components/bridge/AddFundsThroughBridge.tsx @@ -0,0 +1,139 @@ +import { ArrowLeftOutlined } from '@ant-design/icons'; +import { Button, Flex, Image, Typography } from 'antd'; +import { isNil } from 'lodash'; +import { useCallback, useMemo, useState } from 'react'; + +import { Pages } from '@/enums/Pages'; +import { TokenSymbol } from '@/enums/Token'; +import { usePageState } from '@/hooks/usePageState'; +import { toMiddlewareChainFromTokenSymbol } from '@/utils/middlewareHelpers'; + +import { NumberInput } from '../NumberInput'; +import { CardFlex } from '../styled/CardFlex'; + +const { Title, Text } = Typography; + +// TODO: from backend +const fundsToReceive = [ + { + symbol: TokenSymbol.OLAS, + amount: 0, + }, + { + symbol: TokenSymbol.ETH, + amount: 0.005, + }, +]; + +const BridgeHeader = () => { + const { goto } = usePageState(); + + return ( + + + +
      +
      + ); +}; diff --git a/frontend/components/bridge/BridgeTransferFlow.tsx b/frontend/components/bridge/BridgeTransferFlow.tsx new file mode 100644 index 000000000..c2d88523c --- /dev/null +++ b/frontend/components/bridge/BridgeTransferFlow.tsx @@ -0,0 +1,83 @@ +import { ArrowRightOutlined } from '@ant-design/icons'; +import { Flex, List, Typography } from 'antd'; +import { kebabCase } from 'lodash'; +import Image from 'next/image'; +import React from 'react'; + +import { COLOR } from '@/constants/colors'; +import { CrossChainTransferDetails, TokenTransfer } from '@/types/Bridge'; +import { formatUnitsToNumber } from '@/utils/numberFormatters'; + +const { Text } = Typography; + +const TransferChain = ({ chainName }: { chainName: string }) => ( + + chain logo + {chainName} + +); + +const TransferringAndReceivingRow = () => ( + + + Transferring + Receiving + + +); + +const TransferRow = ({ transfer }: { transfer: TokenTransfer }) => { + const { fromAmount, fromSymbol, toSymbol, toAmount, decimals } = transfer; + return ( + + + + {formatUnitsToNumber(fromAmount, decimals, 5)} {fromSymbol} + + + {formatUnitsToNumber(toAmount, decimals, 5)} {toSymbol} + + + + ); +}; + +type BridgeTransferFlowProps = CrossChainTransferDetails; + +/** + * Presentational component for the bridge transfer flow + * showing the transfer details between two chains. + */ +export const BridgeTransferFlow = ({ + fromChain, + toChain, + transfers, +}: BridgeTransferFlowProps) => { + return ( + + + + + + } + renderItem={(transfer, index) => ( + <> + {index === 0 && } + + + )} + bordered + size="small" + /> + ); +}; diff --git a/frontend/components/bridge/BridgingSteps.tsx b/frontend/components/bridge/BridgingSteps.tsx new file mode 100644 index 000000000..321c84999 --- /dev/null +++ b/frontend/components/bridge/BridgingSteps.tsx @@ -0,0 +1,237 @@ +import { LoadingOutlined } from '@ant-design/icons'; +import { Button, Flex, Steps, Typography } from 'antd'; +import { noop } from 'lodash'; +import React, { useMemo } from 'react'; +import styled from 'styled-components'; + +import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { SUPPORT_URL } from '@/constants/urls'; +import { TokenSymbol } from '@/enums/Token'; +import { BridgingStepStatus as Status } from '@/types/Bridge'; +import { Maybe, Nullable } from '@/types/Util'; + +import { ExportLogsButton } from '../ExportLogsButton'; + +const { Text } = Typography; + +const SubStepRow = styled.div` + line-height: normal; +`; + +const Desc = ({ text }: { text: string }) => ( + + {text} + +); + +const TxnDetails = ({ link }: { link: string }) => ( + + + Txn details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + +); + +type FundsAreSafeMessageProps = Pick; +const FundsAreSafeMessage = ({ + onRetry = noop, + onRetryProps, +}: FundsAreSafeMessageProps) => ( + + + {onRetry && ( + + )} + + + + + Don't worry, your funds remain safe. You can access them by importing + your Pearl seed phrase into a compatible wallet, like MetaMask or + Coinbase. + + + + Ask for help in{' '} + + the Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + +); + +type Step = { + title: string; + status: Status; + computedSubSteps: { + description: Nullable; + txnLink: Maybe; + isFailed?: boolean; + onRetry?: () => void; + onRetryProps?: { isLoading: boolean }; + }[]; +}; + +export type StepEvent = { + symbol?: TokenSymbol; + status?: Status; + txnLink?: Maybe; + onRetry?: () => void; + onRetryProps?: { isLoading: boolean }; +}; + +const generateBridgeStep = ( + status: Status, + subSteps: StepEvent[], +): Omit => { + return { + status, + computedSubSteps: subSteps.map( + ({ symbol, status, txnLink, onRetry, onRetryProps }) => { + const isFailed = status === 'error'; + const description = (() => { + if (status === 'finish') { + return `Bridging ${symbol || ''} transaction complete.`; + } + if (status === 'error') { + return `Bridging ${symbol || ''} failed.`; + } + return `Sending transaction...`; + })(); + + return { description, txnLink, isFailed, onRetry, onRetryProps }; + }, + ), + }; +}; + +const generateMasterSafeCreationStep = ( + status: Status, + subSteps: StepEvent[], +): Step => { + const isFailed = status === 'error'; + const description = (() => { + if (status === 'finish') return 'Transaction complete.'; + if (status === 'error') return 'Transaction failed.'; + if (status === 'process') return 'Sending transaction...'; + return null; + })(); + + return { + title: 'Create Master Safe', + status, + computedSubSteps: subSteps.map(({ txnLink }) => { + return { description, txnLink, isFailed }; + }), + }; +}; + +const generateMasterSafeTransferStep = ( + status: Status, + subSteps: StepEvent[], +): Step => { + return { + title: 'Transfer funds to the Master Safe', + status, + computedSubSteps: subSteps.map(({ symbol, status, txnLink }) => { + const isFailed = status === 'error'; + const description = (() => { + if (status === 'finish') { + return `Transfer ${symbol} transaction complete.`; + } + if (status === 'process') { + return 'Sending transaction...'; + } + if (status === 'error') { + return `Transfer ${symbol} transaction failed.`; + } + return null; + })(); + + return { description, txnLink, isFailed }; + }), + }; +}; + +type BridgingStep = { status: Status; subSteps: StepEvent[] }; + +type BridgingStepsProps = { + chainName: string; + bridge: BridgingStep; + masterSafeCreation?: BridgingStep; + masterSafeTransfer?: BridgingStep; +}; + +/** + * Presentational component for the bridging steps. + */ +export const BridgingSteps = ({ + chainName, + bridge, + masterSafeCreation, + masterSafeTransfer, +}: BridgingStepsProps) => { + const bridgeStep: Step = useMemo(() => { + return { + title: `Bridge funds to ${chainName}`, + ...generateBridgeStep(bridge.status, bridge.subSteps), + }; + }, [chainName, bridge]); + + const masterSafeCreationStep: Nullable = useMemo(() => { + if (!masterSafeCreation) return null; + return generateMasterSafeCreationStep( + masterSafeCreation.status, + masterSafeCreation.subSteps, + ); + }, [masterSafeCreation]); + + const masterSafeTransferStep: Nullable = useMemo(() => { + if (!masterSafeTransfer) return null; + return generateMasterSafeTransferStep( + masterSafeTransfer.status, + masterSafeTransfer.subSteps, + ); + }, [masterSafeTransfer]); + + const steps = useMemo( + () => + [bridgeStep, masterSafeCreationStep, masterSafeTransferStep].filter( + (step): step is Step => Boolean(step), + ), + [bridgeStep, masterSafeCreationStep, masterSafeTransferStep], + ); + + return ( + { + return { + status, + title, + description: computedSubSteps.map((subStep, index) => ( + + {subStep.description && } + {subStep.txnLink && } + {subStep.isFailed && ( + + )} + + )), + icon: status === 'process' ? : undefined, + }; + })} + /> + ); +}; diff --git a/frontend/components/bridge/DepositAddress.tsx b/frontend/components/bridge/DepositAddress.tsx new file mode 100644 index 000000000..4a26f05d6 --- /dev/null +++ b/frontend/components/bridge/DepositAddress.tsx @@ -0,0 +1,42 @@ +import { CopyOutlined } from '@ant-design/icons'; +import { Button, Flex, message, Tooltip, Typography } from 'antd'; +import { useCallback } from 'react'; + +import { useMasterWalletContext } from '@/hooks/useWallet'; +import { copyToClipboard } from '@/utils/copyToClipboard'; + +import { LIGHT_ICON_STYLE } from '../ui/iconStyles'; + +const { Text } = Typography; + +// TODO: make a shared component similar to AccountCreationAddress +export const DepositAddress = () => { + const { masterEoa } = useMasterWalletContext(); + const address = masterEoa?.address; + + const handleCopyAddress = useCallback(() => { + if (address) { + copyToClipboard(address).then(() => message.success('Address copied!')); + } + }, [address]); + + return ( + + + + Deposit address + + + + + +); + +type DepositForBridgingProps = { + chainName: string; + updateQuoteId: (quoteId: string) => void; + updateCrossChainTransferDetails: (details: CrossChainTransferDetails) => void; + onNext: () => void; +}; + +export const DepositForBridging = ({ + chainName, + updateQuoteId, + updateCrossChainTransferDetails, + onNext, +}: DepositForBridgingProps) => { + const { selectedAgentConfig } = useServices(); + const toMiddlewareChain = selectedAgentConfig.middlewareHomeChainId; + const { masterEoa } = useMasterWalletContext(); + const { refillRequirements, isBalancesAndFundingRequirementsLoading } = + useBalanceAndRefillRequirementsContext(); + const getBridgeRequirementsParams = useGetBridgeRequirementsParams(); + + const [ + isBridgeRefillRequirementsApiLoading, + setIsBridgeRefillRequirementsApiLoading, + ] = useState(true); + const [isForceUpdate, setIsForceUpdate] = useState(false); + const [ + canPollForBridgeRefillRequirements, + setCanPollForBridgeRefillRequirements, + ] = useState(true); + + const bridgeRequirementsParams = useMemo(() => { + if (!getBridgeRequirementsParams) return null; + return getBridgeRequirementsParams(isForceUpdate); + }, [isForceUpdate, getBridgeRequirementsParams]); + + // force_update: true is used only when the user clicks on "Try again", + // hence reset it to false after the API call is made. + const resetForceUpdate = useCallback(() => setIsForceUpdate(false), []); + + const { + data: bridgeFundingRequirements, + isLoading: isBridgeRefillRequirementsLoading, + isError: isBridgeRefillRequirementsError, + isFetching: isBridgeRefillRequirementsFetching, + refetch: refetchBridgeRefillRequirements, + } = useBridgeRefillRequirements( + bridgeRequirementsParams, + canPollForBridgeRefillRequirements, + isForceUpdate ? resetForceUpdate : undefined, + ); + + // fetch bridge refill requirements manually on mount + useEffect(() => { + if (!isBridgeRefillRequirementsApiLoading) return; + + refetchBridgeRefillRequirements().finally(() => { + setIsBridgeRefillRequirementsApiLoading(false); + }); + }, [ + isBridgeRefillRequirementsApiLoading, + refetchBridgeRefillRequirements, + setIsBridgeRefillRequirementsApiLoading, + ]); + + const isRequestingQuote = + isBalancesAndFundingRequirementsLoading || + isBridgeRefillRequirementsApiLoading || + isBridgeRefillRequirementsLoading; + + const isRequestingQuoteFailed = useMemo(() => { + if (isRequestingQuote) return false; + if (isBridgeRefillRequirementsError) return true; + + // Even if the API call succeeds, if any entry has QUOTE_FAILED, + // we should still display an error message and allow the user to retry. + return bridgeFundingRequirements?.bridge_request_status.some( + (request) => request.status === 'QUOTE_FAILED', + ); + }, [ + isRequestingQuote, + isBridgeRefillRequirementsError, + bridgeFundingRequirements, + ]); + + // If quote has failed, stop polling for bridge refill requirements + useEffect(() => { + if (!isRequestingQuoteFailed) return; + setCanPollForBridgeRefillRequirements(false); + }, [isRequestingQuoteFailed]); + + // List of tokens that need to be deposited + const tokens = useMemo(() => { + if (!bridgeFundingRequirements) return []; + if (!masterEoa) return []; + + const fromMiddlewareChain = MiddlewareChain.ETHEREUM; + + const bridgeTotalRequirements = + bridgeFundingRequirements.bridge_total_requirements[ + fromMiddlewareChain + ]?.[masterEoa.address]; + const bridgeRefillRequirements = + bridgeFundingRequirements.bridge_refill_requirements[ + fromMiddlewareChain + ]?.[masterEoa.address]; + + if (!bridgeTotalRequirements || !bridgeRefillRequirements) return []; + + return Object.entries(bridgeTotalRequirements).map( + ([tokenAddress, totalRequired]) => { + const totalRequiredInWei = BigInt(totalRequired); + + // current balance = total_required_amount - required_amount + // eg. if total_required_amount = 1000 and required_amount = 200, + // then the assumed current_balance = 1000 - 200 = 800 + const currentBalanceInWei = + totalRequiredInWei - + BigInt(bridgeRefillRequirements[tokenAddress as Address] || 0); + + const token = Object.values(ETHEREUM_TOKEN_CONFIG).find((tokenInfo) => { + if (tokenAddress === AddressZero && !tokenInfo.address) return true; + return areAddressesEqual(tokenInfo.address!, tokenAddress); + }); + + if (!token) { + throw new Error( + `Failed to get the token info for the following token address: ${tokenAddress}`, + ); + } + + const areFundsReceived = totalRequiredInWei - currentBalanceInWei <= 0; + + return { + address: tokenAddress as Address, + symbol: token.symbol, + totalRequiredInWei, + currentBalanceInWei, + areFundsReceived, + decimals: token.decimals, + isNative: token.tokenType === TokenType.NativeGas, + } satisfies DepositTokenDetails; + }, + ); + }, [bridgeFundingRequirements, masterEoa]); + + // After the user has deposited the required funds, + // send the quote ID, cross-chain transfer details to the next step + useEffect(() => { + if (isRequestingQuote) return; + if (isBridgeRefillRequirementsFetching) return; + if (!bridgeFundingRequirements) return; + if (tokens.length === 0) return; + if (isRequestingQuoteFailed) return; + if (!masterEoa?.address) return; + + const areAllFundsReceived = + tokens.every((token) => token.areFundsReceived) && + !bridgeFundingRequirements.is_refill_required; + if (!areAllFundsReceived) return; + updateQuoteId(bridgeFundingRequirements.id); + updateCrossChainTransferDetails({ + fromChain: upperFirst(MiddlewareChain.ETHEREUM), + toChain: upperFirst(toMiddlewareChain), + transfers: tokens.map((token) => { + const toAmount = (() => { + // TODO: reuse getFromToken function from utils.ts + + // Find the token address on the destination chain. + // eg. if the token is USDC on Ethereum, it will be USDC on Base + // but the address will be different. + const chainTokenConfig = + TOKEN_CONFIG[asEvmChainId(toMiddlewareChain)][token.symbol]; + const toTokenAddress = + token.symbol === TokenSymbol.ETH + ? token.address + : chainTokenConfig.address; + + if (!toTokenAddress) return BigInt(0); + + const toToken = bridgeRequirementsParams?.bridge_requests?.find( + ({ to }) => areAddressesEqual(to.token, toTokenAddress), + ); + if (!toToken) return BigInt(0); + + return BigInt(toToken.to.amount); + })(); + + return { + fromSymbol: token.symbol, + fromAmount: token.currentBalanceInWei.toString(), + toSymbol: token.symbol, + toAmount: toAmount.toString(), + decimals: token.decimals, + }; + }), + }); + + // wait for 2 seconds before proceeding to the next step. + message.success({ + content: 'Funds received, proceeding to next step...', + key: FUNDS_RECEIVED_MESSAGE_KEY, + }); + delayInSeconds(2).then(() => { + message.destroy(FUNDS_RECEIVED_MESSAGE_KEY); + onNext(); + }); + }, [ + isRequestingQuote, + isBridgeRefillRequirementsFetching, + isRequestingQuoteFailed, + toMiddlewareChain, + refillRequirements, + bridgeFundingRequirements, + masterEoa, + tokens, + bridgeRequirementsParams, + onNext, + updateQuoteId, + updateCrossChainTransferDetails, + ]); + + // Retry to fetch the bridge refill requirements + const handleRetryAgain = useCallback(() => { + setIsForceUpdate(true); + setCanPollForBridgeRefillRequirements(true); + }, []); + + return ( + + + + + {isRequestingQuote ? ( + + ) : isRequestingQuoteFailed ? ( + + ) : ( + <> + + {tokens.length === 0 ? ( + + No tokens to deposit! + + ) : ( + <> + {tokens.map((token) => ( + + ))} + + )} + + + + + )} + + ); +}; diff --git a/frontend/components/bridge/EstimatedCompletionTime.tsx b/frontend/components/bridge/EstimatedCompletionTime.tsx new file mode 100644 index 000000000..393de514f --- /dev/null +++ b/frontend/components/bridge/EstimatedCompletionTime.tsx @@ -0,0 +1,61 @@ +import { Flex, Skeleton, Statistic, Typography } from 'antd'; +import React, { useMemo } from 'react'; +import styled from 'styled-components'; + +const { Text } = Typography; +const { Countdown } = Statistic; + +const EstimatedTimeRow = styled(Flex)` + .ant-statistic .ant-statistic-content .ant-statistic-content-prefix { + margin-inline-end: 0 !important; + } + .ant-statistic .ant-statistic-content .ant-statistic-content-suffix { + margin-inline-start: 0 !important; + } +`; + +type EstimatedCompletionTimeProps = { + isLoading?: boolean; + timeInSeconds: number; +}; + +export const EstimatedCompletionTime = ({ + isLoading, + timeInSeconds, +}: EstimatedCompletionTimeProps) => { + const deadline = useMemo(() => { + if (!timeInSeconds) return 0; + return new Date(timeInSeconds * 1000).getTime(); + }, [timeInSeconds]); + + const minutesRemaining = useMemo(() => { + if (!deadline) return 0; + const minutes = Math.floor((deadline - new Date().getTime()) / 1000 / 60); + return Math.max(0, minutes); + }, [deadline]); + + return ( + + Estimated completion time: + {isLoading ? ( + + ) : ( + <> + + ~ {minutesRemaining} minute{minutesRemaining === 1 ? '' : 's'} + + + + + + )} + + ); +}; diff --git a/frontend/components/bridge/TokenDetails.tsx b/frontend/components/bridge/TokenDetails.tsx new file mode 100644 index 000000000..6c580c53c --- /dev/null +++ b/frontend/components/bridge/TokenDetails.tsx @@ -0,0 +1,95 @@ +import { CheckSquareOutlined, ClockCircleOutlined } from '@ant-design/icons'; +import { Divider, Flex, Typography } from 'antd'; + +import { TokenSymbol } from '@/enums/Token'; +import { Address } from '@/types/Address'; +import { formatUnitsToNumber } from '@/utils/numberFormatters'; + +import { InfoTooltip } from '../InfoTooltip'; +import { SUCCESS_ICON_STYLE, WARNING_ICON_STYLE } from '../ui/iconStyles'; + +const { Text } = Typography; + +export type DepositTokenDetails = { + address?: Address; + symbol: TokenSymbol; + totalRequiredInWei: bigint; + currentBalanceInWei: bigint; + areFundsReceived: boolean; + decimals: number; + isNative?: boolean; + precision?: number; +}; + +export const TokenDetails = ({ + symbol, + totalRequiredInWei, + currentBalanceInWei, + areFundsReceived, + decimals, + isNative, + precision = 2, +}: DepositTokenDetails) => { + const depositRequiredInWei = totalRequiredInWei - currentBalanceInWei; + + return ( + + {areFundsReceived ? ( + <> + + {symbol} funds received! + + ) : ( + <> + + + Waiting for{' '} + + {formatUnitsToNumber(depositRequiredInWei, decimals, precision)} +   + {symbol} + + + + )} + + + + + + Total amount required + + {`${formatUnitsToNumber(totalRequiredInWei, decimals, precision)} ${symbol}`} + + + + Balance at deposit address + + {`${formatUnitsToNumber(currentBalanceInWei, decimals, precision)} ${symbol}`} + + + + + Deposit required + + {`${formatUnitsToNumber(depositRequiredInWei, decimals, precision)} ${symbol}`} + + {isNative && ( + + The total amount may fluctuate due to periodic quote updates. + + )} + + + + ); +}; diff --git a/frontend/components/bridge/types.ts b/frontend/components/bridge/types.ts new file mode 100644 index 000000000..24a6aeae4 --- /dev/null +++ b/frontend/components/bridge/types.ts @@ -0,0 +1 @@ +export type SendFundAction = 'transfer' | 'bridge'; diff --git a/frontend/components/bridge/utils.ts b/frontend/components/bridge/utils.ts new file mode 100644 index 000000000..ef28fc420 --- /dev/null +++ b/frontend/components/bridge/utils.ts @@ -0,0 +1,216 @@ +import { isAddress } from 'ethers/lib/utils'; +import { useCallback } from 'react'; + +import { + AddressBalanceRecord, + MasterSafeBalanceRecord, + MiddlewareChain, +} from '@/client'; +import { + ChainTokenConfig, + ETHEREUM_TOKEN_CONFIG, + TOKEN_CONFIG, +} from '@/config/tokens'; +import { AddressZero } from '@/constants/address'; +import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; +import { useBalanceAndRefillRequirementsContext } from '@/hooks/useBalanceAndRefillRequirementsContext'; +import { useServices } from '@/hooks/useServices'; +import { useMasterWalletContext } from '@/hooks/useWallet'; +import { Address } from '@/types/Address'; +import { BridgeRefillRequirementsRequest } from '@/types/Bridge'; +import { areAddressesEqual } from '@/utils/address'; +import { bigintMax } from '@/utils/calculations'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; + +/** + * Helper to get source token address on the fromChain + */ +const getFromToken = ( + tokenAddress: string, + fromChainConfig: ChainTokenConfig, + toChainConfig: ChainTokenConfig, +): Address => { + if (tokenAddress.toLowerCase() === AddressZero) { + return AddressZero; + } + + const tokenSymbol = Object.values(toChainConfig).find((configToken) => + areAddressesEqual(configToken.address!, tokenAddress), + )?.symbol; + + if (!tokenSymbol || !fromChainConfig[tokenSymbol]?.address) { + throw new Error( + `Failed to get source token for the destination token: ${tokenAddress}`, + ); + } + + return fromChainConfig[tokenSymbol].address as Address; +}; + +/** + * + * @warning A HOOK THAT SHOULD NEVER EXIST. + * @deprecated TODO: This hook is used because BE doesn't support monthly_gas_estimate in the refill requirements yet. + * Remove the hook once it's supported + * + * Hook to return the updated bridge requirements params to improve the + * initial funding requirements. + * + * Request quote with formula (will be moved to backend): + * max(refill_requirement_masterSafe, monthly_gas_estimate) + refill_requirements_masterEOA + * + */ +const useGetBridgeRequirementsParamsWithMonthlyGasEstimate = () => { + const { selectedAgentConfig } = useServices(); + const { masterEoa } = useMasterWalletContext(); + const { refillRequirements, isBalancesAndFundingRequirementsLoading } = + useBalanceAndRefillRequirementsContext(); + + const toMiddlewareChain = selectedAgentConfig.middlewareHomeChainId; + + return useCallback( + (bridgeRequests: BridgeRefillRequirementsRequest['bridge_requests']) => { + if (isBalancesAndFundingRequirementsLoading) return; + if (!refillRequirements) return; + if (!masterEoa?.address) return; + + const nativeTokenIndex = bridgeRequests.findIndex((req) => + areAddressesEqual(req.from.token, AddressZero), + ); + if (nativeTokenIndex === -1) return; + + // refill_requirements_masterEOA + const masterEoaRequirementAmount = ( + refillRequirements as AddressBalanceRecord + )[masterEoa.address][AddressZero]; + + // refill_requirements_masterSafe + const safeRequirementAmount = ( + refillRequirements as MasterSafeBalanceRecord + )['master_safe'][AddressZero]; + + // monthly_gas_estimate + const monthlyGasEstimate = + SERVICE_TEMPLATES.find( + (template) => template.home_chain === toMiddlewareChain, + )?.configurations[toMiddlewareChain].monthly_gas_estimate ?? 0; + + // amount = max(refill_requirement_masterSafe, monthly_gas_estimate) + refill_requirements_masterEOA + const amount = + bigintMax(BigInt(safeRequirementAmount), BigInt(monthlyGasEstimate)) + + BigInt(masterEoaRequirementAmount); + + bridgeRequests[nativeTokenIndex].to.amount = amount.toString(); + + return bridgeRequests; + }, + [ + masterEoa, + refillRequirements, + toMiddlewareChain, + isBalancesAndFundingRequirementsLoading, + ], + ); +}; + +/** + * Helper to get bridge refill requirements parameters + * based on current refill requirements + */ +export const useGetBridgeRequirementsParams = () => { + const { selectedAgentConfig } = useServices(); + const { masterEoa } = useMasterWalletContext(); + const { refillRequirements, isBalancesAndFundingRequirementsLoading } = + useBalanceAndRefillRequirementsContext(); + const getUpdatedBridgeRequirementsParams = + useGetBridgeRequirementsParamsWithMonthlyGasEstimate(); + + const toMiddlewareChain = selectedAgentConfig.middlewareHomeChainId; + const fromAddress = masterEoa?.address; + const toAddress = masterEoa?.address; + + return useCallback( + (isForceUpdate = false) => { + if (isBalancesAndFundingRequirementsLoading) return null; + if (!refillRequirements) return null; + if (!fromAddress || !toAddress) return null; + + const fromChainConfig = ETHEREUM_TOKEN_CONFIG; // TODO: make dynamic, get from token config + const toChainConfig = TOKEN_CONFIG[asEvmChainId(toMiddlewareChain)]; + + const bridgeRequests: BridgeRefillRequirementsRequest['bridge_requests'] = + []; + + const tokensRefillList = Object.entries(refillRequirements); + + // Populate bridge requests from refill Requirements + for (const [walletAddress, tokensWithRequirements] of tokensRefillList) { + // Only calculate the refill requirements from master EOA or master safe placeholder + const isRecipientAddress = areAddressesEqual(walletAddress, toAddress); + if (!(isRecipientAddress || walletAddress === 'master_safe')) { + continue; + } + + for (const [tokenAddress, amount] of Object.entries( + tokensWithRequirements, + )) { + if (!isAddress(tokenAddress)) continue; + + const fromToken = getFromToken( + tokenAddress, + fromChainConfig, + toChainConfig, + ); + + const fromChain = MiddlewareChain.ETHEREUM; + const toChain = toMiddlewareChain; + const toToken = tokenAddress as Address; + + const existingRequest = bridgeRequests.find( + (req) => + req.from.chain === fromChain && + req.to.chain === toChain && + areAddressesEqual(req.from.address, fromAddress) && + areAddressesEqual(req.to.address, toAddress) && + areAddressesEqual(req.from.token, fromToken) && + areAddressesEqual(req.to.token, toToken), + ); + + if (existingRequest) { + // If the request already exists, update the amount + const toAmount = BigInt(existingRequest.to.amount) + BigInt(amount); + existingRequest.to.amount = toAmount.toString(); + } else { + bridgeRequests.push({ + from: { + chain: fromChain, + address: fromAddress, + token: fromToken, + }, + to: { + chain: toChain, + address: toAddress, + token: toToken, + amount: `${amount}`, + }, + }); + } + } + } + + return { + bridge_requests: + getUpdatedBridgeRequirementsParams(bridgeRequests) || bridgeRequests, + force_update: isForceUpdate, + } satisfies BridgeRefillRequirementsRequest; + }, + [ + fromAddress, + toAddress, + refillRequirements, + isBalancesAndFundingRequirementsLoading, + toMiddlewareChain, + getUpdatedBridgeRequirementsParams, + ], + ); +}; diff --git a/frontend/components/styled/CardFlex.tsx b/frontend/components/styled/CardFlex.tsx index 25030cc36..6e7d945f7 100644 --- a/frontend/components/styled/CardFlex.tsx +++ b/frontend/components/styled/CardFlex.tsx @@ -2,24 +2,46 @@ import { Card } from 'antd'; import styled from 'styled-components'; type CardFlexProps = { + /** @deprecated Use $gap instead */ gap?: number; + /** @deprecated Use $noBodyPadding instead */ noBodyPadding?: 'true' | 'false'; + /** @deprecated Use $noBorder instead */ noBorder?: boolean; + $gap?: number; + $noBodyPadding?: boolean; + $noBorder?: boolean; + $padding?: string; }; + export const CardFlex = styled(Card).withConfig({ shouldForwardProp: (prop: string) => !['gap', 'noBodyPadding', 'noBorder'].includes(prop), })` - ${(props) => !!props.noBorder && 'border: none;'} + ${(props) => !!(props.noBorder || props.$noBorder) && 'border: none;'} .ant-card-body { ${(props) => { - const { gap, noBodyPadding } = props; + const { + gap: legacyGap, + $gap, + noBodyPadding: legacyNoBodyPadding, + $noBodyPadding, + } = props; + const gap = legacyGap || $gap; + const noBodyPadding = legacyNoBodyPadding === 'true' || $noBodyPadding; + const gapStyle = gap ? `gap: ${gap}px;` : ''; - const paddingStyle = noBodyPadding === 'true' ? 'padding: 0;' : ''; - return `${gapStyle} ${paddingStyle}`; + const paddingStyle = noBodyPadding + ? 'padding: 0;' + : (props.$padding && `padding: ${props.$padding};`) || ''; + + return ` + display: flex; + flex-direction: column; + ${gapStyle} + ${paddingStyle} + `; }} - display: flex; - flex-direction: column; } `; diff --git a/frontend/components/styled/CardSection.tsx b/frontend/components/styled/CardSection.tsx index 5e28ceb45..4de7dbe10 100644 --- a/frontend/components/styled/CardSection.tsx +++ b/frontend/components/styled/CardSection.tsx @@ -4,10 +4,15 @@ import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; type CardSectionProps = FlexProps & { + /** @deprecated Use $borderTop instead */ bordertop?: 'true' | 'false'; + /** @deprecated Use $borderBottom instead */ borderbottom?: 'true' | 'false'; + /** @deprecated Use $padding instead */ padding?: string; - vertical?: boolean; + $borderTop?: boolean; + $borderBottom?: boolean; + $padding?: string; }; /** @@ -17,19 +22,26 @@ type CardSectionProps = FlexProps & { */ export const CardSection = styled(Flex)` ${(props) => { - const { padding, borderbottom, bordertop } = props; + const { + padding, + borderbottom, + bordertop, + vertical, + $borderBottom, + $borderTop, + $padding, + } = props; - const paddingStyle = `padding: ${padding ?? '0px'};`; + const paddingStyle = `padding: ${(padding || $padding) ?? '0px'};`; const borderTopStyle = - bordertop === 'true' + bordertop === 'true' || $borderTop ? `border-top: 1px solid ${COLOR.BORDER_GRAY};` : 'border-top: none;'; const borderBottomStyle = - borderbottom === 'true' + borderbottom === 'true' || $borderBottom ? `border-bottom: 1px solid ${COLOR.BORDER_GRAY};` : 'border-bottom: none;'; - - const verticalStyle = props.vertical ? 'flex-direction: column;' : ''; + const verticalStyle = vertical ? 'flex-direction: column;' : ''; return ` ${paddingStyle} diff --git a/frontend/components/ui/iconStyles.ts b/frontend/components/ui/iconStyles.ts new file mode 100644 index 000000000..e14176106 --- /dev/null +++ b/frontend/components/ui/iconStyles.ts @@ -0,0 +1,6 @@ +import { COLOR } from '@/constants/colors'; + +export const LIGHT_ICON_STYLE = { color: COLOR.TEXT_LIGHT }; +export const WARNING_ICON_STYLE = { color: COLOR.WARNING }; +export const SUCCESS_ICON_STYLE = { color: COLOR.SUCCESS }; +export const ERROR_ICON_STYLE = { color: COLOR.RED }; diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index 0241de47f..8d4cb44c2 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -42,6 +42,20 @@ export type ChainTokenConfig = { [tokenSymbol: string]: TokenConfig; }; +export const ETHEREUM_TOKEN_CONFIG: ChainTokenConfig = { + [TokenSymbol.ETH]: { + tokenType: TokenType.NativeGas, + decimals: 18, + symbol: TokenSymbol.ETH, + }, + [TokenSymbol.OLAS]: { + address: '0x0001A500A6B18995B03f44bb040A5fFc28E45CB0', + decimals: 18, + tokenType: TokenType.Erc20, + symbol: TokenSymbol.OLAS, + }, +} as const; + const GNOSIS_TOKEN_CONFIG: ChainTokenConfig = { [TokenSymbol.XDAI]: { decimals: 18, @@ -115,6 +129,11 @@ export const MODE_TOKEN_CONFIG: ChainTokenConfig = { }, }; +/** + * TODO: + * 1. combine EvmChainId and AllEvmChainId into one thing to avoid confusion + * 2. include ethereum config into this and make it so balances are not requested for it + */ export const TOKEN_CONFIG: Record = { [EvmChainId.Gnosis]: GNOSIS_TOKEN_CONFIG, [EvmChainId.Base]: BASE_TOKEN_CONFIG, diff --git a/frontend/constants/address.ts b/frontend/constants/address.ts index 4b918c97b..b96c0445b 100644 --- a/frontend/constants/address.ts +++ b/frontend/constants/address.ts @@ -1,3 +1,8 @@ import { ethers } from 'ethers'; +import { Address } from '@/types/Address'; + export const AddressZero = ethers.constants.AddressZero; + +export const ETHEREUM_OLAS_ADDRESS: Address = + '0x0001A500A6B18995B03f44bb040A5fFc28E45CB0'; diff --git a/frontend/constants/colors.ts b/frontend/constants/colors.ts index 1cf8b942f..7c7d0f1b4 100644 --- a/frontend/constants/colors.ts +++ b/frontend/constants/colors.ts @@ -15,4 +15,6 @@ export const COLOR = { NEUTRAL_4: '#A3AEBB', GRAY_1: '#f2f4f9', GRAY_2: '#4D596A', + SUCCESS: '#52C41A', + WARNING: '#FA8C16', }; diff --git a/frontend/constants/intervals.ts b/frontend/constants/intervals.ts index 4c29ead69..242c0f870 100644 --- a/frontend/constants/intervals.ts +++ b/frontend/constants/intervals.ts @@ -2,6 +2,8 @@ export const ONE_SECOND_INTERVAL = 1_000; export const FIVE_SECONDS_INTERVAL = 5 * ONE_SECOND_INTERVAL; +export const TEN_SECONDS_INTERVAL = 10 * ONE_SECOND_INTERVAL; + export const FIFTEEN_SECONDS_INTERVAL = 15 * ONE_SECOND_INTERVAL; export const ONE_MINUTE_INTERVAL = 60 * ONE_SECOND_INTERVAL; diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index a0f1fa277..4fa3a67a3 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -1,4 +1,5 @@ import { Safe } from '@/enums/Wallet'; +import { BridgeRefillRequirementsRequest } from '@/types/Bridge'; import { Maybe } from '@/types/Util'; export const REACT_QUERY_KEYS = { @@ -77,4 +78,11 @@ export const REACT_QUERY_KEYS = { // balances and funding requirements BALANCES_AND_REFILL_REQUIREMENTS_KEY: (serviceConfigId: string) => ['balancesAndRefillRequirements', serviceConfigId] as const, + + // bridge + BRIDGE_REFILL_REQUIREMENTS_KEY: (params: BridgeRefillRequirementsRequest) => + ['bridgeRefillRequirements', params] as const, + BRIDGE_STATUS_BY_QUOTE_ID_KEY: (quoteId: string) => + ['bridgeStatusByQuoteId', quoteId] as const, + BRIDGE_EXECUTE_KEY: (quoteId: string) => ['bridgeExecute', quoteId] as const, } as const; diff --git a/frontend/context/BalancesAndRefillRequirementsProvider.tsx b/frontend/context/BalancesAndRefillRequirementsProvider.tsx index e3be422a6..407ef741a 100644 --- a/frontend/context/BalancesAndRefillRequirementsProvider.tsx +++ b/frontend/context/BalancesAndRefillRequirementsProvider.tsx @@ -1,7 +1,11 @@ -import { useQuery } from '@tanstack/react-query'; +import { QueryObserverResult, useQuery } from '@tanstack/react-query'; import { createContext, PropsWithChildren, useMemo } from 'react'; -import { AddressBalanceRecord, BalancesAndFundingRequirements } from '@/client'; +import { + AddressBalanceRecord, + BalancesAndFundingRequirements, + MasterSafeBalanceRecord, +} from '@/client'; import { FIVE_SECONDS_INTERVAL, ONE_MINUTE_INTERVAL, @@ -12,19 +16,27 @@ import { usePageState } from '@/hooks/usePageState'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { BalanceService } from '@/service/balances'; -import { Optional } from '@/types/Util'; +import { Nullable, Optional } from '@/types/Util'; import { asMiddlewareChain } from '@/utils/middlewareHelpers'; export const BalancesAndRefillRequirementsProviderContext = createContext<{ isBalancesAndFundingRequirementsLoading: boolean; balances: Optional; - refillRequirements: Optional; + refillRequirements: Optional; + totalRequirements: Optional; canStartAgent: boolean; + isRefillRequired: boolean; + refetch: Nullable< + () => Promise> + >; }>({ isBalancesAndFundingRequirementsLoading: false, balances: undefined, refillRequirements: undefined, + totalRequirements: undefined, canStartAgent: false, + isRefillRequired: false, + refetch: null, }); export const BalancesAndRefillRequirementsProvider = ({ @@ -50,6 +62,7 @@ export const BalancesAndRefillRequirementsProvider = ({ const { data: balancesAndRefillRequirements, isLoading: isBalancesAndFundingRequirementsLoading, + refetch, } = useQuery({ queryKey: REACT_QUERY_KEYS.BALANCES_AND_REFILL_REQUIREMENTS_KEY( configId as string, @@ -69,9 +82,9 @@ export const BalancesAndRefillRequirementsProvider = ({ return balancesAndRefillRequirements.balances[asMiddlewareChain(chainId)]; }, [ - balancesAndRefillRequirements, - chainId, isBalancesAndFundingRequirementsLoading, + chainId, + balancesAndRefillRequirements, ]); const refillRequirements = useMemo(() => { @@ -82,9 +95,22 @@ export const BalancesAndRefillRequirementsProvider = ({ asMiddlewareChain(chainId) ]; }, [ - balancesAndRefillRequirements, + isBalancesAndFundingRequirementsLoading, chainId, + balancesAndRefillRequirements, + ]); + + const totalRequirements = useMemo(() => { + if (isBalancesAndFundingRequirementsLoading) return; + if (!balancesAndRefillRequirements) return; + + return balancesAndRefillRequirements.total_requirements[ + asMiddlewareChain(chainId) + ]; + }, [ isBalancesAndFundingRequirementsLoading, + chainId, + balancesAndRefillRequirements, ]); return ( @@ -93,8 +119,12 @@ export const BalancesAndRefillRequirementsProvider = ({ isBalancesAndFundingRequirementsLoading, refillRequirements, balances, + totalRequirements, canStartAgent: balancesAndRefillRequirements?.allow_start_agent || false, + isRefillRequired: + balancesAndRefillRequirements?.is_refill_required || false, + refetch: refetch || null, }} > {children} diff --git a/frontend/context/MasterWalletProvider.tsx b/frontend/context/MasterWalletProvider.tsx index 342ea8b34..ba9796550 100644 --- a/frontend/context/MasterWalletProvider.tsx +++ b/frontend/context/MasterWalletProvider.tsx @@ -1,6 +1,12 @@ import { QueryObserverBaseResult, useQuery } from '@tanstack/react-query'; import { getAddress, isAddress } from 'ethers/lib/utils'; -import { createContext, PropsWithChildren, useContext, useState } from 'react'; +import { + createContext, + PropsWithChildren, + useContext, + useMemo, + useState, +} from 'react'; import { MiddlewareWalletResponse } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; @@ -80,15 +86,24 @@ export const MasterWalletProvider = ({ children }: PropsWithChildren) => { ), }); - const masterEoa = masterWallets?.find( - (wallet): wallet is MasterEoa => - wallet.type === WalletType.EOA && wallet.owner === WalletOwnerType.Master, + const masterEoa = useMemo( + () => + masterWallets?.find( + (wallet): wallet is MasterEoa => + wallet.type === WalletType.EOA && + wallet.owner === WalletOwnerType.Master, + ), + [masterWallets], ); - const masterSafes = masterWallets?.filter( - (wallet): wallet is MasterSafe => - wallet.type === WalletType.Safe && - wallet.owner === WalletOwnerType.Master, + const masterSafes = useMemo( + () => + masterWallets?.filter( + (wallet): wallet is MasterSafe => + wallet.type === WalletType.Safe && + wallet.owner === WalletOwnerType.Master, + ), + [masterWallets], ); return ( diff --git a/frontend/enums/Pages.ts b/frontend/enums/Pages.ts index 721495b36..8850f5fe0 100644 --- a/frontend/enums/Pages.ts +++ b/frontend/enums/Pages.ts @@ -12,4 +12,5 @@ export enum Pages { SwitchAgent, AgentActivity, UpdateAgentTemplate, + AddFundsThroughBridge, } diff --git a/frontend/enums/SetupScreen.ts b/frontend/enums/SetupScreen.ts index 45a29595a..eed9453f5 100644 --- a/frontend/enums/SetupScreen.ts +++ b/frontend/enums/SetupScreen.ts @@ -15,4 +15,7 @@ export enum SetupScreen { RestoreViaBackup, AgentIntroduction, EarlyAccessOnly, + + /** Onboarding using the bridge */ + SetupBridgeOnboardingScreen, } diff --git a/frontend/hooks/useBackupSigner.ts b/frontend/hooks/useBackupSigner.ts new file mode 100644 index 000000000..e6d3f5b63 --- /dev/null +++ b/frontend/hooks/useBackupSigner.ts @@ -0,0 +1,15 @@ +import { useMultisigs } from './useMultisig'; +import { useSetup } from './useSetup'; +import { useMasterWalletContext } from './useWallet'; + +/** + * Hook to get the backup signer address. + */ +export const useBackupSigner = () => { + const { backupSigner } = useSetup(); + const { masterSafes } = useMasterWalletContext(); + const { allBackupAddresses } = useMultisigs(masterSafes); + + const backupSignerAddress = backupSigner ?? allBackupAddresses[0]; + return backupSignerAddress; +}; diff --git a/frontend/hooks/useBridgeRefillRequirements.ts b/frontend/hooks/useBridgeRefillRequirements.ts new file mode 100644 index 000000000..559cbb8fd --- /dev/null +++ b/frontend/hooks/useBridgeRefillRequirements.ts @@ -0,0 +1,37 @@ +import { useQuery } from '@tanstack/react-query'; +import { useContext } from 'react'; + +import { TEN_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { OnlineStatusContext } from '@/context/OnlineStatusProvider'; +import { BridgeService } from '@/service/Bridge'; +import { BridgeRefillRequirementsRequest } from '@/types/Bridge'; + +export const useBridgeRefillRequirements = ( + params: BridgeRefillRequirementsRequest | null, + canPoll: boolean = true, + onSuccess?: () => void, +) => { + const { isOnline } = useContext(OnlineStatusContext); + + return useQuery({ + queryKey: REACT_QUERY_KEYS.BRIDGE_REFILL_REQUIREMENTS_KEY(params!), + queryFn: async ({ signal }) => { + const response = await BridgeService.getBridgeRefillRequirements( + params!, + signal, + ); + + if (onSuccess) onSuccess(); + return response; + }, + + refetchInterval: canPoll ? TEN_SECONDS_INTERVAL : false, + refetchOnWindowFocus: false, + enabled: isOnline && !!params, + staleTime: 0, + refetchOnMount: 'always', + refetchOnReconnect: 'always', + refetchIntervalInBackground: true, + }); +}; diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index 6f60872e7..0cc1b4792 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -15,6 +15,8 @@ const FeatureFlagsSchema = z.enum([ 'agent-activity', 'backup-via-safe', 'agent-settings', + 'bridge-onboarding', + 'bridge-add-funds', ]); type FeatureFlags = z.infer; @@ -39,6 +41,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': true, 'agent-settings': false, + 'bridge-onboarding': false, + 'bridge-add-funds': false, }, [AgentType.Memeooorr]: { 'manage-wallet': true, @@ -50,6 +54,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': true, 'agent-settings': true, + 'bridge-onboarding': true, + 'bridge-add-funds': false, }, [AgentType.AgentsFunCelo]: { 'manage-wallet': true, @@ -61,6 +67,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': true, 'agent-settings': false, + 'bridge-onboarding': false, + 'bridge-add-funds': false, }, [AgentType.Modius]: { 'manage-wallet': true, @@ -72,6 +80,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': false, // temporarily hidden until mode is available on safe https://app.safe.global/new-safe/create 'agent-settings': true, + 'bridge-onboarding': false, + 'bridge-add-funds': false, }, }); diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index 035d05c8c..29d26e224 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -106,18 +106,20 @@ export const useLogs = () => { const { isLoaded: isAddressesLoaded, data: addresses } = useAddressesLogs(); const logs = useMemo(() => { - if (isServicesLoaded && isBalancesLoaded && isAddressesLoaded) { - return { - store: storeState, - debugData: { services, addresses, balances }, - }; - } + return { + store: storeState, + debugData: { + services: isServicesLoaded ? services : null, + addresses: isAddressesLoaded ? addresses : null, + balances: isBalancesLoaded ? balances : null, + }, + }; }, [ - addresses, - balances, isAddressesLoaded, isBalancesLoaded, isServicesLoaded, + addresses, + balances, services, storeState, ]); diff --git a/frontend/hooks/usePageState.ts b/frontend/hooks/usePageState.ts index daad4b3aa..008f38348 100644 --- a/frontend/hooks/usePageState.ts +++ b/frontend/hooks/usePageState.ts @@ -1,4 +1,4 @@ -import { useContext } from 'react'; +import { useCallback, useContext } from 'react'; import { PageStateContext } from '@/context/PageStateProvider'; import { Pages } from '@/enums/Pages'; @@ -6,9 +6,12 @@ import { Pages } from '@/enums/Pages'; export const usePageState = () => { const pageState = useContext(PageStateContext); - const goto = (state: Pages) => { - pageState.setPageState(state); - }; + const goto = useCallback( + (state: Pages) => { + pageState.setPageState(state); + }, + [pageState], + ); return { goto, ...pageState }; }; diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 7547c6b0e..0aaf42c8d 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -2,6 +2,7 @@ import { useEffect, useMemo } from 'react'; import { AgentActivityPage } from '@/components/AgentActivity'; import { AgentSelection } from '@/components/AgentSelection'; +import { AddFundsThroughBridge } from '@/components/bridge/AddFundsThroughBridge'; import { Main } from '@/components/MainPage'; import { ManageStakingPage } from '@/components/ManageStakingPage'; import { AddBackupWalletViaSafePage } from '@/components/Pages/AddBackupWalletViaSafePage'; @@ -67,6 +68,11 @@ export default function Home() { return ; case Pages.UpdateAgentTemplate: return ; + + // bridge pages + case Pages.AddFundsThroughBridge: + return ; + default: return
      ; } diff --git a/frontend/public/chains/base-chain.png b/frontend/public/chains/base-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..38b747114cb007e83cd4e652f5ab7ab2e0ad6596 GIT binary patch literal 2894 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 literal 0 HcmV?d00001 diff --git a/frontend/public/chains/ethereum-chain.png b/frontend/public/chains/ethereum-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..f9685c478d193338893ec9837b3d39b83c00bca5 GIT binary patch literal 2769 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 AYXATM literal 0 HcmV?d00001 diff --git a/frontend/public/olas-icon.png b/frontend/public/olas-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..87e8ff76b6d5d199ebeb0191443d07b8f2401bf6 GIT binary patch literal 35622 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 N>H1Oj--ZAAe*iinSkC|e literal 0 HcmV?d00001 diff --git a/frontend/service/Bridge.ts b/frontend/service/Bridge.ts new file mode 100644 index 000000000..4cbdcd0f5 --- /dev/null +++ b/frontend/service/Bridge.ts @@ -0,0 +1,65 @@ +import { CONTENT_TYPE_JSON_UTF8 } from '@/constants/headers'; +import { BACKEND_URL } from '@/constants/urls'; +import { + BridgeRefillRequirementsRequest, + BridgeRefillRequirementsResponse, + BridgeStatusResponse, +} from '@/types/Bridge'; + +/** + * Get bridge refill requirements for the provided source and destination parameters + */ +const getBridgeRefillRequirements = async ( + params: BridgeRefillRequirementsRequest, + signal?: AbortSignal, +): Promise => + fetch(`${BACKEND_URL}/bridge/bridge_refill_requirements`, { + method: 'POST', + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + body: JSON.stringify(params), + signal, + }).then((response) => { + if (response.ok) return response.json(); + throw new Error( + `Failed to get bridge refill requirements for the following params: ${params}`, + ); + }); + +/** + * Execute bridge for the provided quote bundle id + */ +const executeBridge = async (id: string): Promise => + fetch(`${BACKEND_URL}/bridge/execute`, { + method: 'POST', + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + body: JSON.stringify({ id }), + }).then((response) => { + if (response.ok) return response.json(); + throw new Error( + `Failed to execute bridge quote for the following quote id: ${id}`, + ); + }); + +/** + * Get status of the bridge for the provided quote bundle id + */ +const getBridgeStatus = async ( + id: string, + signal: AbortSignal, +): Promise => + fetch(`${BACKEND_URL}/bridge/status/${id}`, { + method: 'GET', + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + signal, + }).then((response) => { + if (response.ok) return response.json(); + throw new Error( + `Failed to get bridge status for the following quote id: ${id}`, + ); + }); + +export const BridgeService = { + getBridgeRefillRequirements, + executeBridge, + getBridgeStatus, +}; diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index d26a8da35..13f750232 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -1,6 +1,7 @@ import { MiddlewareChain, MiddlewareWalletResponse } from '@/client'; import { CONTENT_TYPE_JSON_UTF8 } from '@/constants/headers'; import { BACKEND_URL } from '@/constants/urls'; +import { SafeCreationResponse } from '@/types/Wallet'; /** * Returns a list of available wallets @@ -23,11 +24,18 @@ const createEoa = async () => throw new Error('Failed to create EOA'); }); -const createSafe = async (chain: MiddlewareChain, backup_owner?: string) => +/** + * @param initial_funds - Funds to be sent to master safe from master EOA + */ +const createSafe = async ( + chain: MiddlewareChain, + backup_owner?: string, + transfer_excess_assets?: boolean, +): Promise => fetch(`${BACKEND_URL}/wallet/safe`, { method: 'POST', headers: { ...CONTENT_TYPE_JSON_UTF8 }, - body: JSON.stringify({ chain, backup_owner, fund_amount: 0 }), + body: JSON.stringify({ chain, backup_owner, transfer_excess_assets }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create safe'); diff --git a/frontend/styles/globals.scss b/frontend/styles/globals.scss index 6863095e8..187ceddf5 100644 --- a/frontend/styles/globals.scss +++ b/frontend/styles/globals.scss @@ -47,6 +47,10 @@ textarea, /* Scrollbar color when hovered */ } +.border-box { + box-sizing: border-box; +} + // antd overrides .ant-card { -webkit-app-region: no-drag; @@ -58,11 +62,6 @@ textarea, } } -.antd-card { - background-color: #FFFFFF; - overflow-y: scroll; -} - .balance { font-family: 'Inter'; font-weight: 900; @@ -150,6 +149,10 @@ textarea, margin-bottom: 8px !important; } +.mb-12 { + margin-bottom: 12px !important; +} + .mb-16 { margin-bottom: 16px !important; } @@ -178,11 +181,23 @@ textarea, margin-top: 12px !important; } +.mt-16 { + margin-top: 16px !important; +} + +.mt-24 { + margin-top: 24px !important; +} + // padding .p-0 { padding: 0 !important; } +.pl-4 { + padding-left: 4px !important; +} + .pl-16 { padding-left: 16px !important; } @@ -191,6 +206,22 @@ textarea, padding-right: 16px !important; } +.pt-16 { + padding-top: 16px !important; +} + +.pt-24 { + padding-top: 24px !important; +} + +.p-8 { + padding: 8px; +} + +.p-16 { + padding: 16px; +} + .p-24 { padding: 24px; } @@ -230,6 +261,10 @@ textarea, color: #4D596A !important; } +.text-lighter { + color: #606F85 !important; +} + .text-right { text-align: right !important; } @@ -273,15 +308,23 @@ ul.alert-list { max-width: 200px; } -.loading-ellipses:after { - overflow: hidden; +.loading-ellipses { display: inline-block; - vertical-align: bottom; - -webkit-animation: ellipsis steps(4, end) 900ms infinite; - animation: ellipsis steps(4, end) 900ms infinite; - content: "\2026"; - /* ascii code for the ellipsis character */ - width: 0px; + position: relative; /* Ensures absolute positioned :after is placed relative to this */ + white-space: nowrap; /* Prevents line breaks */ + margin-right: 16px; + + &:after { + overflow: hidden; + display: inline-block; + -webkit-animation: ellipsis steps(4, end) 1.5s infinite; + animation: ellipsis steps(4, end) 1.5s infinite; + content: "\2026"; /* ascii code for the ellipsis character */ + width: 0px; + position: absolute; + left: 100%; + white-space: nowrap; + } } .hover-underline { diff --git a/frontend/theme/index.ts b/frontend/theme/index.ts index 5f362f54e..48f0524df 100644 --- a/frontend/theme/index.ts +++ b/frontend/theme/index.ts @@ -18,6 +18,8 @@ export const mainTheme: ThemeConfig = { fontSize: 16, }, Button: { + contentFontSizeSM: 14, + paddingInlineSM: 12, fontSize: 16, fontSizeLG: 16, }, @@ -46,6 +48,13 @@ export const mainTheme: ThemeConfig = { Tag: { colorSuccess: '#135200', }, + List: { + colorBorder: '#DFE5EE', + }, + Steps: { + fontSize: 16, + colorError: '#CF1322', + }, }, }; diff --git a/frontend/types/Bridge.ts b/frontend/types/Bridge.ts new file mode 100644 index 000000000..de57c7d4f --- /dev/null +++ b/frontend/types/Bridge.ts @@ -0,0 +1,88 @@ +import { AddressBalanceRecord, MiddlewareChain } from '@/client'; +import { TokenSymbol } from '@/enums/Token'; + +import { Address } from './Address'; +import { Maybe, Nullable } from './Util'; + +/** + * Status of the each step in the bridging process. + * - process: the step is in progress (loading spinner) + * - wait: the step is waiting for the previous step to finish (grayed out) + * - finish: the step is finished (checked) + * - error: the step has failed (red cross) + */ +export type BridgingStepStatus = 'process' | 'wait' | 'finish' | 'error'; + +/** + * Execution status of each bridge step. + * For example, status of bridging ethereum to base. + * + * QUOTE_DONE: A quote is available. + * QUOTE_FAILED: Failed to request a quote. + * EXECUTION_PENDING: Execution submitted and pending to be finalized. + * EXECUTION_DONE: Execution finalized successfully. + * EXECUTION_FAILED: Execution failed. + */ +export type QuoteStatus = + | 'CREATED' + | 'QUOTE_DONE' + | 'QUOTE_FAILED' + | 'EXECUTION_PENDING' + | 'EXECUTION_DONE' + | 'EXECUTION_FAILED'; + +type BridgeFrom = { + chain: MiddlewareChain; + address: Address; + token: Address; +}; +type BridgeTo = BridgeFrom & { amount: string }; + +export type BridgeRefillRequirementsRequest = { + bridge_requests: { from: BridgeFrom; to: BridgeTo }[]; + force_update: boolean; +}; + +export type BridgeRefillRequirementsResponse = { + /** quote bundle Id */ + id: string; + balances: Partial<{ + [chain in MiddlewareChain]: AddressBalanceRecord; + }>; + bridge_total_requirements: Partial<{ + [chain in MiddlewareChain]: AddressBalanceRecord; + }>; + bridge_refill_requirements: Partial<{ + [chain in MiddlewareChain]: AddressBalanceRecord; + }>; + bridge_request_status: { message: Nullable; status: QuoteStatus }[]; + expiration_timestamp: number; + is_refill_required: boolean; +}; + +type QuoteRequestStatus = { + explorer_link: Maybe; + message: Nullable; + status: QuoteStatus; + tx_hash?: Maybe; +}; + +export type BridgeStatusResponse = { + id: string; + status: QuoteStatus; + bridge_request_status: QuoteRequestStatus[]; +}; + +export type TokenTransfer = { + fromSymbol: TokenSymbol; + fromAmount: string; + toSymbol: TokenSymbol; + toAmount: string; + decimals?: number; +}; + +export type CrossChainTransferDetails = { + fromChain: string; + toChain: string; + transfers: TokenTransfer[]; +}; diff --git a/frontend/types/Wallet.ts b/frontend/types/Wallet.ts new file mode 100644 index 000000000..aaa463e3d --- /dev/null +++ b/frontend/types/Wallet.ts @@ -0,0 +1,7 @@ +import { Address } from './Address'; + +export type SafeCreationResponse = { + safe: Address; + message: string; + create_tx?: string; +}; diff --git a/frontend/utils/address.ts b/frontend/utils/address.ts new file mode 100644 index 000000000..e58a846f8 --- /dev/null +++ b/frontend/utils/address.ts @@ -0,0 +1,11 @@ +import { toLower } from 'lodash'; + +import { Address } from '@/types/Address'; + +export const areAddressesEqual = ( + a1?: string | Address, + a2?: string | Address, +) => { + if (!a1 || !a2) return false; + return toLower(a1) === toLower(a2); +}; diff --git a/frontend/utils/calculations.ts b/frontend/utils/calculations.ts new file mode 100644 index 000000000..93aea0c8a --- /dev/null +++ b/frontend/utils/calculations.ts @@ -0,0 +1,9 @@ +/** + * Calculates the maximum value from a list of bigints. + * @param args - List of bigints to compare + * @returns The maximum value among the provided bigints + * @example bigintMax(1n, 2n, 3n); // returns 3n + */ +export function bigintMax(...args: bigint[]): bigint { + return args.reduce((max, val) => (val > max ? val : max)); +} diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts index 8f67fb3b6..726bfdf77 100644 --- a/frontend/utils/middlewareHelpers.ts +++ b/frontend/utils/middlewareHelpers.ts @@ -1,5 +1,6 @@ import { MiddlewareChain } from '@/client'; import { EvmChainId } from '@/enums/Chain'; +import { TokenSymbol } from '@/enums/Token'; /** * Converts middleware chain enums to chain ids @@ -39,3 +40,25 @@ export const asMiddlewareChain = (chainId?: EvmChainId | number) => { } throw new Error(`Invalid chain id: ${chainId}`); }; + +/** + * Converts token symbol to middleware chain enums + */ +export const toMiddlewareChainFromTokenSymbol = ( + tokenSymbol?: TokenSymbol, +): MiddlewareChain | undefined => { + switch (tokenSymbol) { + case 'ETH': + return MiddlewareChain.ETHEREUM; + case 'OLAS': + return MiddlewareChain.GNOSIS; + case 'CELO': + return MiddlewareChain.CELO; + case 'XDAI': + return MiddlewareChain.GNOSIS; + case 'WXDAI': + return MiddlewareChain.GNOSIS; + } + + throw new Error(`Invalid token symbol: ${tokenSymbol}`); +}; diff --git a/frontend/utils/numberFormatters.ts b/frontend/utils/numberFormatters.ts index d9b421acd..a607e39ac 100644 --- a/frontend/utils/numberFormatters.ts +++ b/frontend/utils/numberFormatters.ts @@ -1,8 +1,9 @@ import { BigNumberish, ethers } from 'ethers'; -import { round } from 'lodash'; +import { ceil } from 'lodash'; /** * Displays balance in a human readable format + * e.g. 10000000000 => 1.0B */ export const balanceFormat = ( balance: number | undefined, @@ -33,8 +34,9 @@ export const formatUnits = (value: BigNumberish, decimals = 18): string => { export const formatUnitsToNumber = ( value: BigNumberish, decimals = 18, + precision = 4, ): number => { - return round(parseFloat(formatUnits(value, decimals)), 4); + return ceil(parseFloat(formatUnits(value, decimals)), precision); }; /** diff --git a/poetry.lock b/poetry.lock index daceef17a..5e4774453 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2343,8 +2343,8 @@ web3 = "==6.1.0" [package.source] type = "git" url = "https://github.com/valory-xyz/olas-operate-middleware.git" -reference = "af5b50cc0dc127b8bc8462c85ae3ad2192717c5a" -resolved_reference = "af5b50cc0dc127b8bc8462c85ae3ad2192717c5a" +reference = "d2bece2337ba0f993d521716c4842085a7417154" +resolved_reference = "d2bece2337ba0f993d521716c4842085a7417154" [[package]] name = "open-aea" @@ -2505,13 +2505,13 @@ cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (== [[package]] name = "orderly-set" -version = "5.4.0" +version = "5.4.1" description = "Orderly set" optional = false python-versions = ">=3.8" files = [ - {file = "orderly_set-5.4.0-py3-none-any.whl", hash = "sha256:f0192a7f9ae3385b587b71688353fae491d1ca45878496eb71ea118be1623639"}, - {file = "orderly_set-5.4.0.tar.gz", hash = "sha256:c8ff5ba824abe4eebcbbdd3f646ff3648ad0dd52239319d90056d8d30b6cccdd"}, + {file = "orderly_set-5.4.1-py3-none-any.whl", hash = "sha256:b5e21d21680bd9ef456885db800c5cb4f76a03879880c0175e1b077fb166fd83"}, + {file = "orderly_set-5.4.1.tar.gz", hash = "sha256:a1fb5a4fdc5e234e9e8d8e5c1bbdbc4540f4dfe50d12bf17c8bc5dbf1c9c878d"}, ] [[package]] @@ -4038,4 +4038,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "74e803fcfce91f871e4b9e210d23c69be95d5717101155c1f0396f12fc06e474" +content-hash = "824344b0bfea33935adab92bb85d4457b4f075f411f02dccfca9a8b6414087bc" diff --git a/pyproject.toml b/pyproject.toml index 60c18fb12..0a4e1bbac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ include = [] [tool.poetry.dependencies] python = ">=3.9,<3.12" -olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "af5b50cc0dc127b8bc8462c85ae3ad2192717c5a"} +olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "d2bece2337ba0f993d521716c4842085a7417154"} [build-system] requires = ["poetry-core"] From 08a4cb702e75f80158def108dd6f5437a0ca9e85 Mon Sep 17 00:00:00 2001 From: Mohan Date: Tue, 13 May 2025 20:24:41 +0530 Subject: [PATCH 06/44] fix: build fixes for optimus testing and manage wallet feature (#891) * fix: update middlewareChain type to SupportedMiddlewareChain in AddressLink and Titles components * refactor: remove old optimus version retrieval and update trader binary download in workflows and script * fix: add TODO comment for TypeScript error handling in MigrateButton component * fix: add TODO comment for TypeScript error handling in createService function * fix: update types to use SupportedMiddlewareChain in service types and configurations * fix: update hash for Optimus service template in serviceTemplates.ts * refactor: reorganize chain-related types and update imports for better clarity * refactor: replace asEvmChainName with asEvmChainDetails for improved clarity and consistency * fix: update hash for Optimus service template in serviceTemplates.ts * refactor: move EvmChainId and related constants to a new chains.ts file for better organization --- .github/workflows/release.yml | 7 ------ .github/workflows/release_dev.yml | 7 ------ download_binaries.sh | 9 ------- frontend/client/types.ts | 9 ++++--- frontend/components/AddressLink.tsx | 4 ++-- .../StakingContractSection/MigrateButton.tsx | 1 + .../AddBackupWalletViaSafePage/index.tsx | 2 +- .../SetupPage/Create/SetupCreateSafe.tsx | 12 ++++------ frontend/components/YourWalletPage/Titles.tsx | 4 ++-- .../components/YourWalletPage/YourAgent.tsx | 3 ++- frontend/components/YourWalletPage/index.tsx | 10 ++++---- frontend/constants/chains.ts | 24 +++++++++++++++++++ frontend/constants/serviceTemplates.ts | 2 +- frontend/context/ServicesProvider.tsx | 10 ++++---- frontend/enums/Chain.ts | 22 ++++------------- frontend/enums/StakingProgram.ts | 2 ++ frontend/enums/Wallet.ts | 3 --- frontend/hooks/useService.ts | 4 ++-- frontend/package.json | 5 ++-- frontend/service/Services.ts | 3 ++- frontend/service/agents/Modius.ts | 22 ++++------------- frontend/service/agents/Optimism.ts | 4 +--- frontend/utils/middlewareHelpers.ts | 21 ++++++++++++++++ 23 files changed, 94 insertions(+), 96 deletions(-) create mode 100644 frontend/constants/chains.ts diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5e98156e4..6883f3d34 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -60,15 +60,8 @@ jobs: # Download and build with PyInstaller - name: Get trader bin run: | - trader_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/trader.yaml')); print(config['service_version'])") - echo $trader_version make ./dist/aea_bin - #instead of this one mwe use make; mkdir dist && curl -L -o dist/aea_bin "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_${{ env.OS_ARCH }}" - # -- old optimus getter - # optimus_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/optimus.yaml')); print(config['service_version'])") - # echo $optimus_version - # mkdir dist && curl -L -o dist/aea_bin "https://github.com/valory-xyz/optimus/releases/download/${$optimus_version}/optimus_bin_${{ env.OS_ARCH }}" - name: Build with PyInstaller run: | poetry run pyinstaller operate/tendermint.py --onefile diff --git a/.github/workflows/release_dev.yml b/.github/workflows/release_dev.yml index 18d7aa1ea..ae1143804 100644 --- a/.github/workflows/release_dev.yml +++ b/.github/workflows/release_dev.yml @@ -60,15 +60,8 @@ jobs: # Download and build with PyInstaller - name: Get trader bin run: | - trader_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/trader.yaml')); print(config['service_version'])") - echo $trader_version make ./dist/aea_bin - #instead of this one mwe use make; mkdir dist && curl -L -o dist/aea_bin "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_${{ env.OS_ARCH }}" - # -- old optimus getter - # optimus_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/optimus.yaml')); print(config['service_version'])") - # echo $optimus_version - # mkdir dist && curl -L -o dist/aea_bin "https://github.com/valory-xyz/optimus/releases/download/${$optimus_version}/optimus_bin_${{ env.OS_ARCH }}" - name: Build with PyInstaller run: | poetry run pyinstaller operate/tendermint.py --onefile diff --git a/download_binaries.sh b/download_binaries.sh index 0904caa13..487feed39 100755 --- a/download_binaries.sh +++ b/download_binaries.sh @@ -2,12 +2,3 @@ BIN_DIR="electron/bins/" mkdir -p $BIN_DIR - -trader_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/trader.yaml')); print(config['service_version'])") -# optimus_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/optimus.yaml')); print(config['service_version'])") - -# curl -L -o "${BIN_DIR}aea_bin_x64" "https://github.com/valory-xyz/optimus/releases/download/${optimus_version}/optimus_bin_x64" -# curl -L -o "${BIN_DIR}aea_bin_arm64" "https://github.com/valory-xyz/optimus/releases/download/${optimus_version}/optimus_bin_arm64" - -curl -L -o "${BIN_DIR}aea_bin_x64" "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_x64" -curl -L -o "${BIN_DIR}aea_bin_arm64" "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_arm64" \ No newline at end of file diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 88f2616bc..381565533 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -7,6 +7,7 @@ import { MiddlewareChain, MiddlewareDeploymentStatus, MiddlewareLedger, + SupportedMiddlewareChain, } from './enums'; export type ServiceHash = string; @@ -62,7 +63,7 @@ export type MiddlewareServiceResponse = { hash_history: { [block: string]: string; }; - home_chain: MiddlewareChain; + home_chain: SupportedMiddlewareChain; keys: ServiceKeys[]; service_path?: string; chain_configs: { @@ -81,8 +82,10 @@ export type ServiceTemplate = { description: string; image: string; service_version: string; - home_chain: MiddlewareChain; - configurations: Partial>; + home_chain: SupportedMiddlewareChain; + configurations: Partial< + Record + >; env_variables: { [key: string]: EnvVariableAttributes }; deploy?: boolean; }; diff --git a/frontend/components/AddressLink.tsx b/frontend/components/AddressLink.tsx index 85f7ae16d..8e1220e8f 100644 --- a/frontend/components/AddressLink.tsx +++ b/frontend/components/AddressLink.tsx @@ -1,6 +1,6 @@ import { ReactNode } from 'react'; -import { MiddlewareChain } from '@/client'; +import { SupportedMiddlewareChain } from '@/client'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { EXPLORER_URL_BY_MIDDLEWARE_CHAIN } from '@/constants/urls'; import { Address } from '@/types/Address'; @@ -8,7 +8,7 @@ import { truncateAddress } from '@/utils/truncate'; type AddressLinkProps = { address: Address; - middlewareChain: MiddlewareChain; + middlewareChain: SupportedMiddlewareChain; prefix?: ReactNode; hideLinkArrow?: boolean; }; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index 792cd3ea8..5eb904946 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -142,6 +142,7 @@ export const MigrateButton = ({ configurations: { ...Object.entries(serviceTemplate.configurations).reduce( (acc, [middlewareChain]) => { + // @ts-expect-error TODO: to be fixed acc[middlewareChain] = { staking_program_id: stakingProgramIdToMigrateTo, use_mech_marketplace: diff --git a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx index 1ecb6b65e..59bb97226 100644 --- a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx +++ b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx @@ -1,9 +1,9 @@ import { Card, Flex, Skeleton, Typography } from 'antd'; import { CardTitle } from '@/components/Card/CardTitle'; +import { AllEvmChainId, EvmChainId } from '@/constants/chains'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { DISCORD_TICKET_URL } from '@/constants/urls'; -import { AllEvmChainId, EvmChainId } from '@/enums/Chain'; import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; diff --git a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx index 247dfc04a..0222a964b 100644 --- a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx +++ b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx @@ -7,7 +7,6 @@ import { CardSection } from '@/components/styled/CardSection'; import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { SUPPORT_URL } from '@/constants/urls'; -import { EvmChainName } from '@/enums/Chain'; import { Pages } from '@/enums/Pages'; import { useMultisigs } from '@/hooks/useMultisig'; import { usePageState } from '@/hooks/usePageState'; @@ -16,7 +15,7 @@ import { useSetup } from '@/hooks/useSetup'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { WalletService } from '@/service/Wallet'; import { delayInSeconds } from '@/utils/delay'; -import { asEvmChainId } from '@/utils/middlewareHelpers'; +import { asEvmChainDetails, asEvmChainId } from '@/utils/middlewareHelpers'; const { Text } = Typography; @@ -157,15 +156,12 @@ export const SetupCreateSafe = () => { (async () => { for (const middlewareChain of safeCreationsRequired) { setIsCreatingSafe(true); + const displayName = asEvmChainDetails(middlewareChain).displayName; try { await createSafeWithRetries(middlewareChain, 3); - message.success( - `${EvmChainName[asEvmChainId(middlewareChain)]} account created`, - ); + message.success(`${displayName} account created`); } catch (e) { - message.warning( - `Failed to create ${EvmChainName[asEvmChainId(middlewareChain)]} account`, - ); + message.warning(`Failed to create ${displayName} account`); console.error(e); } } diff --git a/frontend/components/YourWalletPage/Titles.tsx b/frontend/components/YourWalletPage/Titles.tsx index 95487a20e..3206369ef 100644 --- a/frontend/components/YourWalletPage/Titles.tsx +++ b/frontend/components/YourWalletPage/Titles.tsx @@ -1,6 +1,6 @@ import { Flex, Typography } from 'antd'; -import { MiddlewareChain } from '@/client'; +import { SupportedMiddlewareChain } from '@/client'; import { InfoTooltip } from '@/components/InfoTooltip'; import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; @@ -11,7 +11,7 @@ const { Paragraph, Text, Title } = Typography; type SignerTitleProps = { signerAddress: Address; - middlewareChain: MiddlewareChain; + middlewareChain: SupportedMiddlewareChain; }; export const SignerTitle = ({ diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index 45ccfb9f8..f05f7ba92 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -18,6 +18,7 @@ import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { Address } from '@/types/Address'; import { WalletBalance } from '@/types/Balance'; +import { asEvmChainDetails } from '@/utils/middlewareHelpers'; import { balanceFormat } from '@/utils/numberFormatters'; import { isValidServiceId } from '@/utils/service'; import { truncateAddress } from '@/utils/truncate'; @@ -104,7 +105,7 @@ const ServiceAndNftDetails = ({ {serviceNftTokenId} {UNICODE_SYMBOLS.EXTERNAL_LINK} diff --git a/frontend/components/YourWalletPage/index.tsx b/frontend/components/YourWalletPage/index.tsx index e85afbdbd..e90f04a8e 100644 --- a/frontend/components/YourWalletPage/index.tsx +++ b/frontend/components/YourWalletPage/index.tsx @@ -1,5 +1,5 @@ import { ConfigProvider, Flex, Skeleton, ThemeConfig, Typography } from 'antd'; -import { capitalize, isNil } from 'lodash'; +import { isNil } from 'lodash'; import { useMemo } from 'react'; import { AddressLink } from '@/components/AddressLink'; @@ -17,6 +17,7 @@ import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { type Address } from '@/types/Address'; import { Optional } from '@/types/Util'; +import { asEvmChainDetails } from '@/utils/middlewareHelpers'; import { balanceFormat } from '@/utils/numberFormatters'; import { FeatureNotEnabled } from '../FeatureNotEnabled'; @@ -96,7 +97,7 @@ const OlasBalance = () => { return ( - {TokenSymbol.OLAS} ({capitalize(middlewareChain)}) + {TokenSymbol.OLAS} ({asEvmChainDetails(middlewareChain).displayName}) ({ @@ -140,7 +141,8 @@ const MasterSafeNativeBalance = () => { { left: ( - {nativeTokenSymbol} ({capitalize(middlewareChain)}) + {nativeTokenSymbol} ( + {asEvmChainDetails(middlewareChain).displayName}) ), leftClassName: 'text-light', @@ -193,7 +195,7 @@ const MasterSafeErc20Balances = () => { { left: ( - {symbol} ({capitalize(middlewareChain)}) + {symbol} ({asEvmChainDetails(middlewareChain).displayName}) ), leftClassName: 'text-light', diff --git a/frontend/constants/chains.ts b/frontend/constants/chains.ts new file mode 100644 index 000000000..06acb7139 --- /dev/null +++ b/frontend/constants/chains.ts @@ -0,0 +1,24 @@ +export const EvmChainId = { + Gnosis: 100, + Base: 8453, + Mode: 34443, + Celo: 42220, + Optimism: 10, +} as const; + +export const EvmChainName = { + [EvmChainId.Gnosis]: 'Gnosis', + [EvmChainId.Base]: 'Base', + [EvmChainId.Mode]: 'Mode', + [EvmChainId.Celo]: 'Celo', + [EvmChainId.Optimism]: 'Optimism', +} as const; + +export const AllEvmChainId = { + Ethereum: 1, + Gnosis: EvmChainId.Gnosis, + Base: EvmChainId.Base, + Mode: EvmChainId.Mode, + Celo: EvmChainId.Celo, + Optimism: EvmChainId.Optimism, +} as const; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 98bca5e9a..a9c951601 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -404,7 +404,7 @@ export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { export const OPTIMUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Optimus, name: 'Optimus - Optimism', - hash: 'bafybeiaatol6ujhey6wlijc3uk57k74bj4yqaehobpfrch7kjxnvghpqgy', + hash: 'bafybeienicyxffuxlwcacwr3qfj4ijvaih4opziogwncs2japau6vzh4bu', description: 'Optimus service deployment on Optimism network', image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index d8d9d539d..5b4332854 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -23,7 +23,7 @@ import { AgentType } from '@/enums/Agent'; import { AgentEoa, AgentSafe, - AgentWallets, + AgentWallet, WalletOwnerType, WalletType, } from '@/enums/Wallet'; @@ -46,7 +46,7 @@ type ServicesResponse = Pick< type ServicesContextType = { services?: MiddlewareServiceResponse[]; - serviceWallets?: AgentWallets; + serviceWallets?: AgentWallet[]; selectedService?: Service; selectedServiceStatusOverride?: Maybe; isSelectedServiceDeploymentStatusLoading: boolean; @@ -161,16 +161,16 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { return config; }, [selectedAgentType]); - const serviceWallets: Optional = useMemo(() => { + const serviceWallets: Optional = useMemo(() => { if (isServicesLoading) return; if (isNilOrEmpty(services)) return []; - return services.reduce( + return services.reduce( (acc, service: MiddlewareServiceResponse) => { return [ ...acc, ...Object.keys(service.chain_configs).reduce( - (acc: AgentWallets, middlewareChain: string) => { + (acc: AgentWallet[], middlewareChain: string) => { const chainConfig = service.chain_configs[middlewareChain as MiddlewareChain]; diff --git a/frontend/enums/Chain.ts b/frontend/enums/Chain.ts index 74e791b01..e9c29a631 100644 --- a/frontend/enums/Chain.ts +++ b/frontend/enums/Chain.ts @@ -1,3 +1,8 @@ +/** + * @deprecated + * + * use `EvmChainId` from `@/types/Chain.ts` instead + */ export enum EvmChainId { Gnosis = 100, Base = 8453, @@ -5,20 +10,3 @@ export enum EvmChainId { Celo = 42220, Optimism = 10, } - -export const EvmChainName = { - [EvmChainId.Gnosis]: 'Gnosis', - [EvmChainId.Base]: 'Base', - [EvmChainId.Mode]: 'Mode', - [EvmChainId.Celo]: 'Celo', - [EvmChainId.Optimism]: 'Optimism', -} as const; - -export enum AllEvmChainId { - Ethereum = 1, - Gnosis = EvmChainId.Gnosis, - Base = EvmChainId.Base, - Mode = EvmChainId.Mode, - Celo = EvmChainId.Celo, - Optimism = EvmChainId.Optimism, -} diff --git a/frontend/enums/StakingProgram.ts b/frontend/enums/StakingProgram.ts index aab958ebe..deafe2489 100644 --- a/frontend/enums/StakingProgram.ts +++ b/frontend/enums/StakingProgram.ts @@ -30,6 +30,8 @@ const MODE_STAKING_PROGRAM_IDS = { OptimusAlpha: 'optimus_alpha', } as const; +export type ModeStakingProgramId = ValueOf; + export const OPTIMISM_STAKING_PROGRAM_IDS = { OptimusAlpha1: 'optimus_alpha', // OptimusAlpha2: 'optimus_alpha_2', diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts index 056e7ff4b..bedd7fcec 100644 --- a/frontend/enums/Wallet.ts +++ b/frontend/enums/Wallet.ts @@ -37,6 +37,3 @@ export type AgentSafe = Safe & { owner: WalletOwnerType.Agent }; export type MasterWallet = MasterEoa | MasterSafe; export type AgentWallet = AgentEoa | AgentSafe; export type Wallet = MasterWallet | AgentWallet; - -/** @deprecated use AgentWallet[] instead */ -export type AgentWallets = AgentWallet[]; diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index df6467376..4e1bd5c7e 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -10,7 +10,7 @@ import { EvmChainId } from '@/enums/Chain'; import { AgentEoa, AgentSafe, - AgentWallets, + AgentWallet, WalletOwnerType, WalletType, } from '@/enums/Wallet'; @@ -53,7 +53,7 @@ export const useService = (serviceConfigId?: string) => { return service?.chain_configs?.[service?.home_chain]?.chain_data.token; }, [service?.chain_configs, service?.home_chain]); - const serviceWallets: AgentWallets = useMemo(() => { + const serviceWallets: AgentWallet[] = useMemo(() => { if (!service) return []; if (!selectedService?.home_chain) return []; if (!service.chain_configs?.[selectedService?.home_chain]) return []; diff --git a/frontend/package.json b/frontend/package.json index fefa0dc0b..ef1ef2315 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -56,7 +56,8 @@ "build": "bash -c \"GNOSIS_RPC=$GNOSIS_RPC BASE_RPC=$BASE_RPC OPTIMISM_RPC=$OPTIMISM_RPC ETHEREUM_RPC=$ETHEREUM_RPC MODE_RPC=$MODE_RPC CELO_RPC=$CELO_RPC NODE_ENV=production next build\"", "lint": "next lint", "test": "jest", - "start": "next start" + "start": "next start", + "check": "yarn run lint && tsc --noEmit --incremental false" }, "version": "0.1.0" -} \ No newline at end of file +} diff --git a/frontend/service/Services.ts b/frontend/service/Services.ts index e8d0c7d3d..d08846bb9 100644 --- a/frontend/service/Services.ts +++ b/frontend/service/Services.ts @@ -3,6 +3,7 @@ import { MiddlewareServiceResponse, ServiceConfigId, ServiceTemplate, + SupportedMiddlewareChain, } from '@/client'; import { CHAIN_CONFIG } from '@/config/chains'; import { CONTENT_TYPE_JSON_UTF8 } from '@/constants/headers'; @@ -75,7 +76,7 @@ const createService = async ({ // overwrite defaults with chain-specific configurations ...Object.entries(serviceTemplate.configurations).reduce( (acc, [middlewareChain, config]) => { - acc[middlewareChain] = { + acc[middlewareChain as SupportedMiddlewareChain] = { ...config, rpc: CHAIN_CONFIG[asEvmChainId(middlewareChain)].rpc, staking_program_id: stakingProgramId, diff --git a/frontend/service/agents/Modius.ts b/frontend/service/agents/Modius.ts index bbe2df543..04e98c790 100644 --- a/frontend/service/agents/Modius.ts +++ b/frontend/service/agents/Modius.ts @@ -5,7 +5,7 @@ import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { MODE_STAKING_PROGRAMS } from '@/config/stakingPrograms/mode'; import { PROVIDERS } from '@/constants/providers'; import { EvmChainId } from '@/enums/Chain'; -import { StakingProgramId } from '@/enums/StakingProgram'; +import { ModeStakingProgramId, StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; import { ServiceStakingDetails, @@ -68,22 +68,6 @@ export abstract class ModiusService extends StakedAgentService { currentMultisigNonces, ] = multicallResponse; - /** - * struct ServiceInfo { - // Service multisig address - address multisig; - // Service owner - address owner; - // Service multisig nonces - uint256[] nonces; <-- (we use this in the rewards eligibility check) - // Staking start time - uint256 tsStart; - // Accumulated service staking reward - uint256 reward; - // Accumulated inactivity that might lead to the service eviction - uint256 inactivity;} - */ - const lastMultisigNonces = serviceInfo[2]; const nowInSeconds = Math.floor(Date.now() / 1000); @@ -190,7 +174,9 @@ export abstract class ModiusService extends StakedAgentService { ): Promise => { const { multicallProvider } = PROVIDERS[chainId]; - const stakingTokenProxy = MODE_STAKING_PROGRAMS[stakingProgramId]?.contract; + const modeStakingProgram = + MODE_STAKING_PROGRAMS[stakingProgramId as ModeStakingProgramId]; + const stakingTokenProxy = modeStakingProgram?.contract; if (!stakingTokenProxy) return; const contractCalls = [ diff --git a/frontend/service/agents/Optimism.ts b/frontend/service/agents/Optimism.ts index a0229dc26..d6e1eaa48 100644 --- a/frontend/service/agents/Optimism.ts +++ b/frontend/service/agents/Optimism.ts @@ -239,9 +239,7 @@ export abstract class OptimismService extends StakedAgentService { maxNumServices, serviceIds, minimumStakingDuration: minStakingDurationInBN.toNumber(), - minStakingDeposit: parseFloat( - ethers.utils.formatEther(minStakingDeposit), - ), + minStakingDeposit: parseFloat(formatEther(minStakingDeposit)), apy, olasStakeRequired, rewardsPerWorkPeriod, diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts index 861741d88..561eafb91 100644 --- a/frontend/utils/middlewareHelpers.ts +++ b/frontend/utils/middlewareHelpers.ts @@ -24,6 +24,27 @@ export const asEvmChainId = (chain?: MiddlewareChain | string): EvmChainId => { throw new Error(`Invalid middleware chain enum: ${chain}`); }; +export const asEvmChainDetails = ( + chain?: MiddlewareChain | string, +): { + name: string; + displayName: string; +} => { + switch (chain) { + case MiddlewareChain.GNOSIS: + return { name: 'gnosis', displayName: 'Gnosis' }; + case MiddlewareChain.BASE: + return { name: 'base', displayName: 'Base' }; + case MiddlewareChain.CELO: + return { name: 'celo', displayName: 'Celo' }; + case MiddlewareChain.MODE: + return { name: 'mode', displayName: 'Mode' }; + case MiddlewareChain.OPTIMISM: + return { name: 'optimism', displayName: 'Optimism' }; + } + throw new Error(`Invalid middleware chain enum: ${chain}`); +}; + /** * Converts chain ids to middleware chain enums * @example asMiddlewareChain(1) => 'ethereum' From 9e7993e1bab8599f67a699c26ce7f2db32a82f7f Mon Sep 17 00:00:00 2001 From: Atatakai Date: Tue, 13 May 2025 19:56:52 +0400 Subject: [PATCH 07/44] release: 0.2.0-rc270 --- package.json | 2 +- poetry.lock | 83 ++++++++++++++++++++++++++------------------------ pyproject.toml | 4 +-- 3 files changed, 46 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index f7cee5e3a..9c5ddb0d8 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "start:frontend": "cd frontend && yarn start", "test:frontend": "cd frontend && yarn test" }, - "version": "0.2.0-rc260", + "version": "0.2.0-rc270", "engine": { "node": ">=20", "yarn": ">=1.22.0", diff --git a/poetry.lock b/poetry.lock index 5e4774453..baa61f7a3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2012,8 +2012,11 @@ files = [ {file = "lxml-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7ce1a171ec325192c6a636b64c94418e71a1964f56d002cc28122fceff0b6121"}, {file = "lxml-5.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:795f61bcaf8770e1b37eec24edf9771b307df3af74d1d6f27d812e15a9ff3872"}, {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29f451a4b614a7b5b6c2e043d7b64a15bd8304d7e767055e8ab68387a8cacf4e"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f7f991a68d20c75cb13c5c9142b2a3f9eb161f1f12a9489c82172d1f133c0"}, {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aa412a82e460571fad592d0f93ce9935a20090029ba08eca05c614f99b0cc92"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:ac7ba71f9561cd7d7b55e1ea5511543c0282e2b6450f122672a2694621d63b7e"}, {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:c5d32f5284012deaccd37da1e2cd42f081feaa76981f0eaa474351b68df813c5"}, + {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:ce31158630a6ac85bddd6b830cffd46085ff90498b397bd0a259f59d27a12188"}, {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:31e63621e073e04697c1b2d23fcb89991790eef370ec37ce4d5d469f40924ed6"}, {file = "lxml-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:be2ba4c3c5b7900246a8f866580700ef0d538f2ca32535e991027bdaba944063"}, {file = "lxml-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:09846782b1ef650b321484ad429217f5154da4d6e786636c38e434fa32e94e49"}, @@ -2298,7 +2301,7 @@ nicer-shell = ["ipython"] [[package]] name = "olas-operate-middleware" -version = "0.3.4" +version = "0.3.5" description = "" optional = false python-versions = "<3.12,>=3.9" @@ -2327,11 +2330,11 @@ hexbytes = "==0.3.1" ipfshttpclient = "==0.8.0a2" jsonschema = "==4.3.3" multidict = "==6.0.5" -open-aea-cli-ipfs = "==1.64.0" -open-aea-ledger-cosmos = "==1.64.0" -open-aea-ledger-ethereum = "==1.64.0" -open-aea-ledger-ethereum-flashbots = "==1.64.0" -open-autonomy = "==0.19.4" +open-aea-cli-ipfs = "==1.65.0" +open-aea-ledger-cosmos = "==1.65.0" +open-aea-ledger-ethereum = "==1.65.0" +open-aea-ledger-ethereum-flashbots = "==1.65.0" +open-autonomy = "==0.19.8" psutil = "^5.9.8" pyinstaller = "^6.8.0" requests-toolbelt = "1.0.0" @@ -2343,23 +2346,23 @@ web3 = "==6.1.0" [package.source] type = "git" url = "https://github.com/valory-xyz/olas-operate-middleware.git" -reference = "d2bece2337ba0f993d521716c4842085a7417154" -resolved_reference = "d2bece2337ba0f993d521716c4842085a7417154" +reference = "5c81ef95597f756e539f4017e3bb1e63f9225f1c" +resolved_reference = "5c81ef95597f756e539f4017e3bb1e63f9225f1c" [[package]] name = "open-aea" -version = "1.64.0" +version = "1.65.0" description = "Open Autonomous Economic Agent framework (without vendor lock-in)" optional = false python-versions = ">=3.8" files = [ - {file = "open_aea-1.64.0-py3-none-any.whl", hash = "sha256:aa1f4c125ede428a17147f3428b42b968503139bd8041a87c3b38b151f8ed9f6"}, - {file = "open_aea-1.64.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9f6eefa9000208e625f61e0bab8070fe244a4dc948de46ad2cbba48e69ff803b"}, - {file = "open_aea-1.64.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:4e627fba9ec368182cfec54c26c961cb399a468da9a2d49c61bac7f9883f88f4"}, - {file = "open_aea-1.64.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:a320979d530aadad6a7d87e488459013ee1c070fe163ee5c3c1cdb01b63e9be7"}, - {file = "open_aea-1.64.0-py3-none-win32.whl", hash = "sha256:3501fbcbe4ec3b34d2f5dcd91403ee4dbd089a0afc98b21baf7f6b6607d64005"}, - {file = "open_aea-1.64.0-py3-none-win_amd64.whl", hash = "sha256:948d52ae67b867987588d6ac462fe35d4782a0696a9fdc191ab028634365f93b"}, - {file = "open_aea-1.64.0.tar.gz", hash = "sha256:d39b997fe8c29403b9266e548cbd01aeea5725fbb397c42e718af50b93b4c5e5"}, + {file = "open_aea-1.65.0-py3-none-any.whl", hash = "sha256:e6353ccc29014e1015acabc4b4b83756bbfc955d6f0a8fa9e8104f3daef5eb5a"}, + {file = "open_aea-1.65.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:bdba7028bb7c85e1ec267d0dbdf372843a2492c5cf220c4d6badc45bd206c31d"}, + {file = "open_aea-1.65.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:d0195e1eeae6620cf04898800fad0bc89f460c5d4c4e89e5e54f8d4ced7337b2"}, + {file = "open_aea-1.65.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:fc636b22af8c3160911e857692126ab7dadf5af834ed5b52559e4ab9c3d4935f"}, + {file = "open_aea-1.65.0-py3-none-win32.whl", hash = "sha256:b3bddcb64ec1852f59d6c730ad1ee825b0243d8bd4d25c744b5087ae40f0e04d"}, + {file = "open_aea-1.65.0-py3-none-win_amd64.whl", hash = "sha256:5fdba41e7ffafd47e56e83f20fec4d764b5db5a57fba56c39c134ef1c602d479"}, + {file = "open_aea-1.65.0.tar.gz", hash = "sha256:7be549fd41ae423f527146c80435bf4a5002dd85d2e4cef368f344e8641aab80"}, ] [package.dependencies] @@ -2387,13 +2390,13 @@ test-tools = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>= [[package]] name = "open-aea-cli-ipfs" -version = "1.64.0" +version = "1.65.0" description = "CLI extension for open AEA framework wrapping IPFS functionality." optional = false python-versions = "*" files = [ - {file = "open_aea_cli_ipfs-1.64.0-py3-none-any.whl", hash = "sha256:79fb5373100735efa3b294ce1ab643d2dd1e2502b4e11da449131d7aee082ff6"}, - {file = "open_aea_cli_ipfs-1.64.0.tar.gz", hash = "sha256:69088d5c8b192ef11ae692a1ae4dab4fa934ba466e9033df76195985aa17f773"}, + {file = "open_aea_cli_ipfs-1.65.0-py3-none-any.whl", hash = "sha256:5f1e730d0821bf5b85c3dc8cc049e94a885b7ea042e8cf1cf573956576d91a49"}, + {file = "open_aea_cli_ipfs-1.65.0.tar.gz", hash = "sha256:2e9875b1b334aa3f949fa2e52c4870f697c9550d02bbde1847fff603fb069205"}, ] [package.dependencies] @@ -2418,13 +2421,13 @@ web3 = ">=6.0.0,<7" [[package]] name = "open-aea-ledger-cosmos" -version = "1.64.0" +version = "1.65.0" description = "Python package wrapping the public and private key cryptography and ledger api of Cosmos." optional = false python-versions = "*" files = [ - {file = "open_aea_ledger_cosmos-1.64.0-py3-none-any.whl", hash = "sha256:1bc4752e696871588c391659c0df5907eccc4d938f3b14a4fa5346cc04ad953f"}, - {file = "open_aea_ledger_cosmos-1.64.0.tar.gz", hash = "sha256:c836c753c8a4150ea49f19723dce808e357243bdebceb556dbc46abb0d2a6f14"}, + {file = "open_aea_ledger_cosmos-1.65.0-py3-none-any.whl", hash = "sha256:58a5816c2dc7657cf26a93a934958f3f1b5f7744664770cf182903cd74a0aa22"}, + {file = "open_aea_ledger_cosmos-1.65.0.tar.gz", hash = "sha256:8da7f5081ff569eb4caa9a7c2a3afe9c03aa9d0d81f060746f949596ae344304"}, ] [package.dependencies] @@ -2436,13 +2439,13 @@ pycryptodome = ">=3.10.1,<4.0.0" [[package]] name = "open-aea-ledger-ethereum" -version = "1.64.0" +version = "1.65.0" description = "Python package wrapping the public and private key cryptography and ledger api of Ethereum." optional = false python-versions = "*" files = [ - {file = "open_aea_ledger_ethereum-1.64.0-py3-none-any.whl", hash = "sha256:0d34ef8292c437a3f8102bd7489d12b5f5000013639bee71f5fb09e84eabe413"}, - {file = "open_aea_ledger_ethereum-1.64.0.tar.gz", hash = "sha256:5de862d87be2ef47b8f4c7de7802956b3f214f9bfbfc8369dfcb638702b070b8"}, + {file = "open_aea_ledger_ethereum-1.65.0-py3-none-any.whl", hash = "sha256:88d0f571a2a0f247cfe581ac8a4273541da1bf4e9e7ae88197ed24e945f26ba4"}, + {file = "open_aea_ledger_ethereum-1.65.0.tar.gz", hash = "sha256:7ee3e58e6eee025008f7f2550fdfc315b41bb1e3d961187ef760a196995134c1"}, ] [package.dependencies] @@ -2453,28 +2456,28 @@ web3 = ">=6.0.0,<7" [[package]] name = "open-aea-ledger-ethereum-flashbots" -version = "1.64.0" +version = "1.65.0" description = "Python package extending the default open-aea ethereum ledger plugin to add support for flashbots." optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "open_aea_ledger_ethereum_flashbots-1.64.0-py3-none-any.whl", hash = "sha256:d0f1e82a63b9aad9c492abf9dd8a8001a3abdf45430c6895e1e129e3e3f94b1c"}, - {file = "open_aea_ledger_ethereum_flashbots-1.64.0.tar.gz", hash = "sha256:63ad60cea5aa8db305e753a9b4df77ba2cdbcb51958f702d4b4c8f41911f7209"}, + {file = "open_aea_ledger_ethereum_flashbots-1.65.0-py3-none-any.whl", hash = "sha256:c52116341b36b7ac99d263161f25b5d38ea815aef611e8a74e306660888baf7b"}, + {file = "open_aea_ledger_ethereum_flashbots-1.65.0.tar.gz", hash = "sha256:2a660f3c5ba4e38fdcd919cd8fd8b03ebea54ba1a08de0896249499e47a6f9a2"}, ] [package.dependencies] open-aea-flashbots = "1.4.0" -open-aea-ledger-ethereum = ">=1.64.0,<1.65.0" +open-aea-ledger-ethereum = ">=1.65.0,<1.66.0" [[package]] name = "open-autonomy" -version = "0.19.4" +version = "0.19.8" description = "A framework for the creation of autonomous agent services." optional = false python-versions = ">=3.8" files = [ - {file = "open_autonomy-0.19.4-py3-none-any.whl", hash = "sha256:c48155be8e0f8e844bcdb78cfc2f231e86f15e2bc853b13a27a545fbc9286ee4"}, - {file = "open_autonomy-0.19.4.tar.gz", hash = "sha256:16ee3ffbb7ba82f076ec2af86e42d063f582b58395b370cd1575522306a93498"}, + {file = "open_autonomy-0.19.8-py3-none-any.whl", hash = "sha256:561802ef6e5ca4487a669bb59c7cc8d395e95561c59e051466169bb896df36fd"}, + {file = "open_autonomy-0.19.8.tar.gz", hash = "sha256:04d1c570c37c6edead57b2f573621d06953ee2f39db91d245e7b59a4e15c039b"}, ] [package.dependencies] @@ -2486,8 +2489,8 @@ Flask = ">=2.0.2,<3.0.0" gql = "3.5.0" hexbytes = "*" jsonschema = ">=4.3.0,<4.4.0" -open-aea = {version = "1.64.0", extras = ["all"]} -open-aea-cli-ipfs = "1.64.0" +open-aea = {version = "1.65.0", extras = ["all"]} +open-aea-cli-ipfs = "1.65.0" protobuf = ">=4.21.6,<4.25.0" pytest = "7.2.1" python-dotenv = ">=0.14.5,<0.22.0" @@ -2500,18 +2503,18 @@ watchdog = ">=2.1.6" werkzeug = "2.0.3" [package.extras] -all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.64.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] -cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.64.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.65.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.65.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] [[package]] name = "orderly-set" -version = "5.4.1" +version = "5.4.0" description = "Orderly set" optional = false python-versions = ">=3.8" files = [ - {file = "orderly_set-5.4.1-py3-none-any.whl", hash = "sha256:b5e21d21680bd9ef456885db800c5cb4f76a03879880c0175e1b077fb166fd83"}, - {file = "orderly_set-5.4.1.tar.gz", hash = "sha256:a1fb5a4fdc5e234e9e8d8e5c1bbdbc4540f4dfe50d12bf17c8bc5dbf1c9c878d"}, + {file = "orderly_set-5.4.0-py3-none-any.whl", hash = "sha256:f0192a7f9ae3385b587b71688353fae491d1ca45878496eb71ea118be1623639"}, + {file = "orderly_set-5.4.0.tar.gz", hash = "sha256:c8ff5ba824abe4eebcbbdd3f646ff3648ad0dd52239319d90056d8d30b6cccdd"}, ] [[package]] @@ -4038,4 +4041,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "824344b0bfea33935adab92bb85d4457b4f075f411f02dccfca9a8b6414087bc" +content-hash = "2da1ef3facb5fcb81bcd420586a87899d63298708dcb537e7d70767891db0c3e" diff --git a/pyproject.toml b/pyproject.toml index 0a4e1bbac..c278341c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-app" -version = "0.2.0-rc260" +version = "0.2.0-rc270" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" @@ -9,7 +9,7 @@ include = [] [tool.poetry.dependencies] python = ">=3.9,<3.12" -olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "d2bece2337ba0f993d521716c4842085a7417154"} +olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "5c81ef95597f756e539f4017e3bb1e63f9225f1c"} [build-system] requires = ["poetry-core"] From 1ce38a99f8fca7a45b65242ebbd54bc78731ff75 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 13 May 2025 18:53:49 +0200 Subject: [PATCH 08/44] chore: update middleware --- poetry.lock | 47 ++++++++++++++++++++++++++--------------------- pyproject.toml | 2 +- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/poetry.lock b/poetry.lock index baa61f7a3..09474dfe3 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1072,21 +1072,26 @@ cython = ["cython"] [[package]] name = "deepdiff" -version = "8.4.2" +version = "8.5.0" description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "deepdiff-8.4.2-py3-none-any.whl", hash = "sha256:7e39e5b26f3747c54f9d0e8b9b29daab670c3100166b77cc0185d5793121b099"}, - {file = "deepdiff-8.4.2.tar.gz", hash = "sha256:5c741c0867ebc7fcb83950ad5ed958369c17f424e14dee32a11c56073f4ee92a"}, + {file = "deepdiff-8.5.0-py3-none-any.whl", hash = "sha256:d4599db637f36a1c285f5fdfc2cd8d38bde8d8be8636b65ab5e425b67c54df26"}, + {file = "deepdiff-8.5.0.tar.gz", hash = "sha256:a4dd3529fa8d4cd5b9cbb6e3ea9c95997eaa919ba37dac3966c1b8f872dc1cd1"}, ] [package.dependencies] -orderly-set = ">=5.3.0,<6" +orderly-set = ">=5.4.1,<6" [package.extras] -cli = ["click (==8.1.8)", "pyyaml (==6.0.2)"] +cli = ["click (>=8.1.0,<8.2.0)", "pyyaml (>=6.0.0,<6.1.0)"] +coverage = ["coverage (>=7.6.0,<7.7.0)"] +dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)", "jsonpickle (>=4.0.0,<4.1.0)", "nox (==2025.5.1)", "numpy (>=2.0,<3.0)", "numpy (>=2.2.0,<2.3.0)", "orjson (>=3.10.0,<3.11.0)", "pandas (>=2.2.0,<2.3.0)", "polars (>=1.21.0,<1.22.0)", "python-dateutil (>=2.9.0,<2.10.0)", "tomli (>=2.2.0,<2.3.0)", "tomli-w (>=1.2.0,<1.3.0)"] +docs = ["Sphinx (>=6.2.0,<6.3.0)", "sphinx-sitemap (>=2.6.0,<2.7.0)", "sphinxemoji (>=0.3.0,<0.4.0)"] optimize = ["orjson"] +static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)", "pydantic (>=2.10.0,<2.11.0)"] +test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"] [[package]] name = "distro" @@ -1343,15 +1348,18 @@ test = ["hypothesis (>=4.43.0)", "mypy (==0.971)", "pytest (>=7.0.0)", "pytest-x [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] @@ -2012,11 +2020,8 @@ files = [ {file = "lxml-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7ce1a171ec325192c6a636b64c94418e71a1964f56d002cc28122fceff0b6121"}, {file = "lxml-5.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:795f61bcaf8770e1b37eec24edf9771b307df3af74d1d6f27d812e15a9ff3872"}, {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29f451a4b614a7b5b6c2e043d7b64a15bd8304d7e767055e8ab68387a8cacf4e"}, - {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f7f991a68d20c75cb13c5c9142b2a3f9eb161f1f12a9489c82172d1f133c0"}, {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aa412a82e460571fad592d0f93ce9935a20090029ba08eca05c614f99b0cc92"}, - {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:ac7ba71f9561cd7d7b55e1ea5511543c0282e2b6450f122672a2694621d63b7e"}, {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:c5d32f5284012deaccd37da1e2cd42f081feaa76981f0eaa474351b68df813c5"}, - {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:ce31158630a6ac85bddd6b830cffd46085ff90498b397bd0a259f59d27a12188"}, {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:31e63621e073e04697c1b2d23fcb89991790eef370ec37ce4d5d469f40924ed6"}, {file = "lxml-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:be2ba4c3c5b7900246a8f866580700ef0d538f2ca32535e991027bdaba944063"}, {file = "lxml-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:09846782b1ef650b321484ad429217f5154da4d6e786636c38e434fa32e94e49"}, @@ -2346,8 +2351,8 @@ web3 = "==6.1.0" [package.source] type = "git" url = "https://github.com/valory-xyz/olas-operate-middleware.git" -reference = "5c81ef95597f756e539f4017e3bb1e63f9225f1c" -resolved_reference = "5c81ef95597f756e539f4017e3bb1e63f9225f1c" +reference = "00397bccf9596a90970604a62de5218d7d70e25e" +resolved_reference = "00397bccf9596a90970604a62de5218d7d70e25e" [[package]] name = "open-aea" @@ -2508,13 +2513,13 @@ cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (== [[package]] name = "orderly-set" -version = "5.4.0" +version = "5.4.1" description = "Orderly set" optional = false python-versions = ">=3.8" files = [ - {file = "orderly_set-5.4.0-py3-none-any.whl", hash = "sha256:f0192a7f9ae3385b587b71688353fae491d1ca45878496eb71ea118be1623639"}, - {file = "orderly_set-5.4.0.tar.gz", hash = "sha256:c8ff5ba824abe4eebcbbdd3f646ff3648ad0dd52239319d90056d8d30b6cccdd"}, + {file = "orderly_set-5.4.1-py3-none-any.whl", hash = "sha256:b5e21d21680bd9ef456885db800c5cb4f76a03879880c0175e1b077fb166fd83"}, + {file = "orderly_set-5.4.1.tar.gz", hash = "sha256:a1fb5a4fdc5e234e9e8d8e5c1bbdbc4540f4dfe50d12bf17c8bc5dbf1c9c878d"}, ] [[package]] @@ -3435,13 +3440,13 @@ files = [ [[package]] name = "setuptools" -version = "80.3.1" +version = "80.4.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" files = [ - {file = "setuptools-80.3.1-py3-none-any.whl", hash = "sha256:ea8e00d7992054c4c592aeb892f6ad51fe1b4d90cc6947cc45c45717c40ec537"}, - {file = "setuptools-80.3.1.tar.gz", hash = "sha256:31e2c58dbb67c99c289f51c16d899afedae292b978f8051efaf6262d8212f927"}, + {file = "setuptools-80.4.0-py3-none-any.whl", hash = "sha256:6cdc8cb9a7d590b237dbe4493614a9b75d0559b888047c1f67d49ba50fc3edb2"}, + {file = "setuptools-80.4.0.tar.gz", hash = "sha256:5a78f61820bc088c8e4add52932ae6b8cf423da2aff268c23f813cfbb13b4006"}, ] [package.extras] @@ -4041,4 +4046,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "2da1ef3facb5fcb81bcd420586a87899d63298708dcb537e7d70767891db0c3e" +content-hash = "e6474a9e15cfeb9fe78e2f7d3169519f28db68c2b2dc5ad71019b4b4f2abef99" diff --git a/pyproject.toml b/pyproject.toml index c278341c2..c5bdda9bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ include = [] [tool.poetry.dependencies] python = ">=3.9,<3.12" -olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "5c81ef95597f756e539f4017e3bb1e63f9225f1c"} +olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "00397bccf9596a90970604a62de5218d7d70e25e"} [build-system] requires = ["poetry-core"] From a9b58bd5e7c55b37e55c1bdf09b60d1e1d4a5791 Mon Sep 17 00:00:00 2001 From: Mohan Date: Thu, 22 May 2025 18:51:41 +0530 Subject: [PATCH 09/44] feat: modius bridging (#915) * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: enable modius bridging (#914) * feat: update ETHEREUM_TOKEN_CONFIG to include USDC and enable bridge onboarding feature * fix: update fund requirements structure and adjust values for testing * fix: update chain name in BridgingSteps component to use dynamic value * fix: refactor logic for mapping bridge total requirements to improve readability * fix: update fund requirements for MODIUS_SERVICE_TEMPLATE to correct values * feat: modius bridge add alert (#918) * fix: update funding message to include dynamic chain name * feat: enhance BridgeOnEvm with CustomAlert and layout adjustments * feat: update address type usage in agents and service modules (#922) * feat: modius bridge safe creation update (#924) * feat: enforce transfer of excess assets during safe creation * feat: enhance FundsAreSafeMessage with additional retry suggestion * feat: improve bridge retry logic and user feedback * feat: update success message for bridge completion --------- Co-authored-by: jmoreira-valory --- frontend/client/types.ts | 10 +- .../BridgeInProgress/BridgeInProgress.tsx | 15 ++- .../useMasterSafeCreationAndTransfer.ts | 1 - .../BridgeInProgress/useRetryBridge.ts | 13 ++- .../SetupBridgeOnboarding/BridgeOnEvm.tsx | 37 +++++-- .../SetupPage/Create/SetupEoaFunding.tsx | 5 +- frontend/components/bridge/BridgingSteps.tsx | 7 +- .../components/bridge/DepositForBridging.tsx | 69 +++++++------ frontend/config/agents.ts | 3 +- frontend/config/tokens.ts | 6 ++ frontend/hooks/useFeatureFlag.ts | 2 +- frontend/service/Wallet.ts | 3 +- frontend/styles/globals.scss | 1 + frontend/utils/service.ts | 5 +- poetry.lock | 96 +++++++++++-------- pyproject.toml | 2 +- 16 files changed, 166 insertions(+), 109 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index ec5d3732d..0d2218967 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -99,15 +99,13 @@ export type ConfigurationTemplate = { monthly_gas_estimate: number; fund_requirements: { // zero address means native currency - [tokenAddress: string]: FundRequirementsTemplate; + [tokenAddress: Address]: { + agent: number; + safe: number; + }; }; }; -export type FundRequirementsTemplate = { - agent: number; - safe: number; -}; - export type DeployedNodes = { agent: string[]; tendermint: string[]; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx index 3780b572a..2218f745f 100644 --- a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx @@ -1,5 +1,5 @@ import { Typography } from 'antd'; -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { CustomAlert } from '@/components/Alert'; import { BridgeTransferFlow } from '@/components/bridge/BridgeTransferFlow'; @@ -63,6 +63,7 @@ export const BridgeInProgress = ({ const { goto } = usePageState(); const symbols = transfers.map((transfer) => transfer.toSymbol); + const [isBridgeRetrying, setIsBridgeRetrying] = useState(false); const refetchBridgeExecute = useRetryBridge(); const { isBridging, isBridgingFailed, isBridgingCompleted, bridgeStatus } = @@ -136,9 +137,12 @@ export const BridgeInProgress = ({ ]); const onBridgeFailRetry = useCallback(() => { + setIsBridgeRetrying(true); refetchBridgeExecute((e: Nullable) => onBridgeRetryOutcome(e), - ); + ).finally(() => { + setIsBridgeRetrying(false); + }); }, [refetchBridgeExecute, onBridgeRetryOutcome]); const bridgeDetails = useMemo(() => { @@ -157,7 +161,9 @@ export const BridgeInProgress = ({ subSteps: (bridgeStatus || []).map((step) => ({ ...step, onRetry: onBridgeFailRetry, - onRetryProps: { isLoading: currentBridgeStatus === 'process' }, + onRetryProps: { + isLoading: currentBridgeStatus === 'process' || isBridgeRetrying, + }, })) satisfies StepEvent[], }; }, [ @@ -166,6 +172,7 @@ export const BridgeInProgress = ({ isBridgingFailed, isBridgingCompleted, bridgeStatus, + isBridgeRetrying, onBridgeFailRetry, ]); @@ -242,7 +249,7 @@ export const BridgeInProgress = ({ /> {!!bridgeDetails && ( { if (!refetch) return; const { data } = await refetch(); - onRetryOutcome(data?.is_refill_required ? 'NEED_REFILL' : null); + if (!data) return; + + if (data?.is_refill_required) { + onRetryOutcome('NEED_REFILL'); + } else { + message.open({ + icon: null, + content: + "Bridging complete! Please restart the app if you're not redirected automatically.", + }); + } }, [refetch], ); diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx index a80e61cee..4f5d9e629 100644 --- a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx @@ -1,5 +1,6 @@ -import { Typography } from 'antd'; +import { Flex, Typography } from 'antd'; +import { CustomAlert } from '@/components/Alert'; import { DepositForBridging } from '@/components/bridge/DepositForBridging'; import { CardFlex } from '@/components/styled/CardFlex'; import { CardSection } from '@/components/styled/CardSection'; @@ -27,14 +28,32 @@ export const BridgeOnEvm = ({ - - - Bridge from {FROM_CHAIN_NAME} - - - The bridged amount covers all funds required to create your account - and run your agent, including fees. No further funds will be needed. - + + + + Bridge from {FROM_CHAIN_NAME} + + + The bridged amount covers all funds required to create your account + and run your agent, including fees. No further funds will be needed. + + + + + + Only send funds on Ethereum! + + Full amount of funds is required to initiate the bridging. + + + } + /> + ( <> - Send funds on Base to create your account. Additional funds for staking - and operating your agent will be requested separately. + Send funds on {chainName} to create your account. Additional funds for + staking and operating your agent will be requested separately. @@ -184,6 +184,7 @@ const SetupEoaFundingForChainV2 = ({ } /> + ( type FundsAreSafeMessageProps = Pick; const FundsAreSafeMessage = ({ - onRetry = noop, + onRetry, onRetryProps, }: FundsAreSafeMessageProps) => ( @@ -64,6 +63,10 @@ const FundsAreSafeMessage = ({ the Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + You can also try restarting the app! + ); diff --git a/frontend/components/bridge/DepositForBridging.tsx b/frontend/components/bridge/DepositForBridging.tsx index 6ac8fd552..29862dd9b 100644 --- a/frontend/components/bridge/DepositForBridging.tsx +++ b/frontend/components/bridge/DepositForBridging.tsx @@ -187,41 +187,40 @@ export const DepositForBridging = ({ if (!bridgeTotalRequirements || !bridgeRefillRequirements) return []; - return Object.entries(bridgeTotalRequirements).map( - ([tokenAddress, totalRequired]) => { - const totalRequiredInWei = BigInt(totalRequired); - - // current balance = total_required_amount - required_amount - // eg. if total_required_amount = 1000 and required_amount = 200, - // then the assumed current_balance = 1000 - 200 = 800 - const currentBalanceInWei = - totalRequiredInWei - - BigInt(bridgeRefillRequirements[tokenAddress as Address] || 0); - - const token = Object.values(ETHEREUM_TOKEN_CONFIG).find((tokenInfo) => { - if (tokenAddress === AddressZero && !tokenInfo.address) return true; - return areAddressesEqual(tokenInfo.address!, tokenAddress); - }); - - if (!token) { - throw new Error( - `Failed to get the token info for the following token address: ${tokenAddress}`, - ); - } - - const areFundsReceived = totalRequiredInWei - currentBalanceInWei <= 0; - - return { - address: tokenAddress as Address, - symbol: token.symbol, - totalRequiredInWei, - currentBalanceInWei, - areFundsReceived, - decimals: token.decimals, - isNative: token.tokenType === TokenType.NativeGas, - } satisfies DepositTokenDetails; - }, - ); + const totalRequirements = Object.entries(bridgeTotalRequirements); + return totalRequirements.map(([tokenAddress, totalRequired]) => { + const totalRequiredInWei = BigInt(totalRequired); + + // current balance = total_required_amount - required_amount + // eg. if total_required_amount = 1000 and required_amount = 200, + // then the assumed current_balance = 1000 - 200 = 800 + const currentBalanceInWei = + totalRequiredInWei - + BigInt(bridgeRefillRequirements[tokenAddress as Address] || 0); + + const token = Object.values(ETHEREUM_TOKEN_CONFIG).find((tokenInfo) => { + if (tokenAddress === AddressZero && !tokenInfo.address) return true; + return areAddressesEqual(tokenInfo.address!, tokenAddress); + }); + + if (!token) { + throw new Error( + `Failed to get the token info for the following token address: ${tokenAddress}`, + ); + } + + const areFundsReceived = totalRequiredInWei - currentBalanceInWei <= 0; + + return { + address: tokenAddress as Address, + symbol: token.symbol, + totalRequiredInWei, + currentBalanceInWei, + areFundsReceived, + decimals: token.decimals, + isNative: token.tokenType === TokenType.NativeGas, + } satisfies DepositTokenDetails; + }); }, [bridgeFundingRequirements, masterEoa]); // After the user has deposited the required funds, diff --git a/frontend/config/agents.ts b/frontend/config/agents.ts index 74638fee9..d69eacd37 100644 --- a/frontend/config/agents.ts +++ b/frontend/config/agents.ts @@ -8,6 +8,7 @@ import { TokenSymbol } from '@/enums/Token'; import { AgentsFunBaseService } from '@/service/agents/AgentsFunBase'; import { ModiusService } from '@/service/agents/Modius'; import { PredictTraderService } from '@/service/agents/PredictTrader'; +import { Address } from '@/types/Address'; import { AgentConfig } from '@/types/Agent'; import { MODE_TOKEN_CONFIG } from './tokens'; @@ -17,7 +18,7 @@ const modiusFundRequirements = .fund_requirements; const modiusUsdcConfig = modiusFundRequirements?.[ - MODE_TOKEN_CONFIG[TokenSymbol.USDC].address as string + MODE_TOKEN_CONFIG[TokenSymbol.USDC].address as Address ]; export const AGENT_CONFIG: { diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index 8d4cb44c2..75d222dc5 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -54,6 +54,12 @@ export const ETHEREUM_TOKEN_CONFIG: ChainTokenConfig = { tokenType: TokenType.Erc20, symbol: TokenSymbol.OLAS, }, + [TokenSymbol.USDC]: { + address: '0xA0b86991c6218b36c1d19D4a2e9EB0CE3606EB48', + decimals: 6, + tokenType: TokenType.Erc20, + symbol: TokenSymbol.USDC, + }, } as const; const GNOSIS_TOKEN_CONFIG: ChainTokenConfig = { diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index 0cc1b4792..c18b79055 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -80,7 +80,7 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': false, // temporarily hidden until mode is available on safe https://app.safe.global/new-safe/create 'agent-settings': true, - 'bridge-onboarding': false, + 'bridge-onboarding': true, 'bridge-add-funds': false, }, }); diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index 13f750232..f84ca69bc 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -30,12 +30,11 @@ const createEoa = async () => const createSafe = async ( chain: MiddlewareChain, backup_owner?: string, - transfer_excess_assets?: boolean, ): Promise => fetch(`${BACKEND_URL}/wallet/safe`, { method: 'POST', headers: { ...CONTENT_TYPE_JSON_UTF8 }, - body: JSON.stringify({ chain, backup_owner, transfer_excess_assets }), + body: JSON.stringify({ chain, backup_owner, transfer_excess_assets: true }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create safe'); diff --git a/frontend/styles/globals.scss b/frontend/styles/globals.scss index 187ceddf5..7fbf0df03 100644 --- a/frontend/styles/globals.scss +++ b/frontend/styles/globals.scss @@ -252,6 +252,7 @@ textarea, .text-center { text-align: center !important; } + .text-right { text-align: right !important; } diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index e58d1959b..aff98060d 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -4,6 +4,7 @@ import { EnvProvisionType, ServiceTemplate } from '@/client'; import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; import { AgentType } from '@/enums/Agent'; import { ServicesService } from '@/service/Services'; +import { Address } from '@/types/Address'; import { Service } from '@/types/Service'; import { DeepPartial } from '@/types/Util'; @@ -85,8 +86,8 @@ export const updateServiceIfNeeded = async ( if ( Object.entries(serviceHomeChainFundRequirements).some(([key, item]) => { return ( - templateFundRequirements[key].agent !== item.agent || - templateFundRequirements[key].safe !== item.safe + templateFundRequirements[key as Address].agent !== item.agent || + templateFundRequirements[key as Address].safe !== item.safe ); }) ) { diff --git a/poetry.lock b/poetry.lock index 09474dfe3..1032ea90d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2306,7 +2306,7 @@ nicer-shell = ["ipython"] [[package]] name = "olas-operate-middleware" -version = "0.3.5" +version = "0.4.0" description = "" optional = false python-versions = "<3.12,>=3.9" @@ -2351,8 +2351,8 @@ web3 = "==6.1.0" [package.source] type = "git" url = "https://github.com/valory-xyz/olas-operate-middleware.git" -reference = "00397bccf9596a90970604a62de5218d7d70e25e" -resolved_reference = "00397bccf9596a90970604a62de5218d7d70e25e" +reference = "c737adcf63bc89d21141a505fcdce53fead4df65" +resolved_reference = "c737adcf63bc89d21141a505fcdce53fead4df65" [[package]] name = "open-aea" @@ -2581,18 +2581,18 @@ files = [ [[package]] name = "pluggy" -version = "1.5.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "propcache" @@ -2796,40 +2796,52 @@ files = [ [[package]] name = "pycryptodome" -version = "3.22.0" +version = "3.23.0" description = "Cryptographic library for Python" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "pycryptodome-3.22.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:96e73527c9185a3d9b4c6d1cfb4494f6ced418573150be170f6580cb975a7f5a"}, - {file = "pycryptodome-3.22.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:9e1bb165ea1dc83a11e5dbbe00ef2c378d148f3a2d3834fb5ba4e0f6fd0afe4b"}, - {file = "pycryptodome-3.22.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:d4d1174677855c266eed5c4b4e25daa4225ad0c9ffe7584bb1816767892545d0"}, - {file = "pycryptodome-3.22.0-cp27-cp27m-win32.whl", hash = "sha256:9dbb749cef71c28271484cbef684f9b5b19962153487735411e1020ca3f59cb1"}, - {file = "pycryptodome-3.22.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:f1ae7beb64d4fc4903a6a6cca80f1f448e7a8a95b77d106f8a29f2eb44d17547"}, - {file = "pycryptodome-3.22.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a26bcfee1293b7257c83b0bd13235a4ee58165352be4f8c45db851ba46996dc6"}, - {file = "pycryptodome-3.22.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:009e1c80eea42401a5bd5983c4bab8d516aef22e014a4705622e24e6d9d703c6"}, - {file = "pycryptodome-3.22.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3b76fa80daeff9519d7e9f6d9e40708f2fce36b9295a847f00624a08293f4f00"}, - {file = "pycryptodome-3.22.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a31fa5914b255ab62aac9265654292ce0404f6b66540a065f538466474baedbc"}, - {file = "pycryptodome-3.22.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0092fd476701eeeb04df5cc509d8b739fa381583cda6a46ff0a60639b7cd70d"}, - {file = "pycryptodome-3.22.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d5b0ddc7cf69231736d778bd3ae2b3efb681ae33b64b0c92fb4626bb48bb89"}, - {file = "pycryptodome-3.22.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f6cf6aa36fcf463e622d2165a5ad9963b2762bebae2f632d719dfb8544903cf5"}, - {file = "pycryptodome-3.22.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:aec7b40a7ea5af7c40f8837adf20a137d5e11a6eb202cde7e588a48fb2d871a8"}, - {file = "pycryptodome-3.22.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d21c1eda2f42211f18a25db4eaf8056c94a8563cd39da3683f89fe0d881fb772"}, - {file = "pycryptodome-3.22.0-cp37-abi3-win32.whl", hash = "sha256:f02baa9f5e35934c6e8dcec91fcde96612bdefef6e442813b8ea34e82c84bbfb"}, - {file = "pycryptodome-3.22.0-cp37-abi3-win_amd64.whl", hash = "sha256:d086aed307e96d40c23c42418cbbca22ecc0ab4a8a0e24f87932eeab26c08627"}, - {file = "pycryptodome-3.22.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:98fd9da809d5675f3a65dcd9ed384b9dc67edab6a4cda150c5870a8122ec961d"}, - {file = "pycryptodome-3.22.0-pp27-pypy_73-win32.whl", hash = "sha256:37ddcd18284e6b36b0a71ea495a4c4dca35bb09ccc9bfd5b91bfaf2321f131c1"}, - {file = "pycryptodome-3.22.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b4bdce34af16c1dcc7f8c66185684be15f5818afd2a82b75a4ce6b55f9783e13"}, - {file = "pycryptodome-3.22.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2988ffcd5137dc2d27eb51cd18c0f0f68e5b009d5fec56fbccb638f90934f333"}, - {file = "pycryptodome-3.22.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e653519dedcd1532788547f00eeb6108cc7ce9efdf5cc9996abce0d53f95d5a9"}, - {file = "pycryptodome-3.22.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5810bc7494e4ac12a4afef5a32218129e7d3890ce3f2b5ec520cc69eb1102ad"}, - {file = "pycryptodome-3.22.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7514a1aebee8e85802d154fdb261381f1cb9b7c5a54594545145b8ec3056ae6"}, - {file = "pycryptodome-3.22.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:56c6f9342fcb6c74e205fbd2fee568ec4cdbdaa6165c8fde55dbc4ba5f584464"}, - {file = "pycryptodome-3.22.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87a88dc543b62b5c669895caf6c5a958ac7abc8863919e94b7a6cafd2f64064f"}, - {file = "pycryptodome-3.22.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a683bc9fa585c0dfec7fa4801c96a48d30b30b096e3297f9374f40c2fedafc"}, - {file = "pycryptodome-3.22.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8f4f6f47a7f411f2c157e77bbbda289e0c9f9e1e9944caa73c1c2e33f3f92d6e"}, - {file = "pycryptodome-3.22.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6cf9553b29624961cab0785a3177a333e09e37ba62ad22314ebdbb01ca79840"}, - {file = "pycryptodome-3.22.0.tar.gz", hash = "sha256:fd7ab568b3ad7b77c908d7c3f7e167ec5a8f035c64ff74f10d47a4edd043d723"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6"}, + {file = "pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef"}, ] [[package]] @@ -3440,13 +3452,13 @@ files = [ [[package]] name = "setuptools" -version = "80.4.0" +version = "80.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" files = [ - {file = "setuptools-80.4.0-py3-none-any.whl", hash = "sha256:6cdc8cb9a7d590b237dbe4493614a9b75d0559b888047c1f67d49ba50fc3edb2"}, - {file = "setuptools-80.4.0.tar.gz", hash = "sha256:5a78f61820bc088c8e4add52932ae6b8cf423da2aff268c23f813cfbb13b4006"}, + {file = "setuptools-80.8.0-py3-none-any.whl", hash = "sha256:95a60484590d24103af13b686121328cc2736bee85de8936383111e421b9edc0"}, + {file = "setuptools-80.8.0.tar.gz", hash = "sha256:49f7af965996f26d43c8ae34539c8d99c5042fbff34302ea151eaa9c207cd257"}, ] [package.extras] @@ -4046,4 +4058,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "e6474a9e15cfeb9fe78e2f7d3169519f28db68c2b2dc5ad71019b4b4f2abef99" +content-hash = "a553ded59c6fdf572c007f7c333024d6a53d2625f1af3cd64be051ac9939374b" diff --git a/pyproject.toml b/pyproject.toml index 0dfbfbbdf..6f095a541 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ include = [] [tool.poetry.dependencies] python = ">=3.9,<3.12" -olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "00397bccf9596a90970604a62de5218d7d70e25e"} +olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "c737adcf63bc89d21141a505fcdce53fead4df65"} [build-system] requires = ["poetry-core"] From c94a69e0b44851c8985ae25da7fb474a2c26fa6a Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 22 May 2025 15:26:02 +0200 Subject: [PATCH 10/44] chore: update middleware --- poetry.lock | 140 ++++++++++++++++++++++++------------------------- pyproject.toml | 2 +- 2 files changed, 71 insertions(+), 71 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1032ea90d..509ee702e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -829,74 +829,74 @@ requests = "*" [[package]] name = "coverage" -version = "7.8.0" +version = "7.8.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2931f66991175369859b5fd58529cd4b73582461877ecfd859b6549869287ffe"}, - {file = "coverage-7.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:52a523153c568d2c0ef8826f6cc23031dc86cffb8c6aeab92c4ff776e7951b28"}, - {file = "coverage-7.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c8a5c139aae4c35cbd7cadca1df02ea8cf28a911534fc1b0456acb0b14234f3"}, - {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a26c0c795c3e0b63ec7da6efded5f0bc856d7c0b24b2ac84b4d1d7bc578d676"}, - {file = "coverage-7.8.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:821f7bcbaa84318287115d54becb1915eece6918136c6f91045bb84e2f88739d"}, - {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a321c61477ff8ee705b8a5fed370b5710c56b3a52d17b983d9215861e37b642a"}, - {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ed2144b8a78f9d94d9515963ed273d620e07846acd5d4b0a642d4849e8d91a0c"}, - {file = "coverage-7.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:042e7841a26498fff7a37d6fda770d17519982f5b7d8bf5278d140b67b61095f"}, - {file = "coverage-7.8.0-cp310-cp310-win32.whl", hash = "sha256:f9983d01d7705b2d1f7a95e10bbe4091fabc03a46881a256c2787637b087003f"}, - {file = "coverage-7.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:5a570cd9bd20b85d1a0d7b009aaf6c110b52b5755c17be6962f8ccd65d1dbd23"}, - {file = "coverage-7.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e7ac22a0bb2c7c49f441f7a6d46c9c80d96e56f5a8bc6972529ed43c8b694e27"}, - {file = "coverage-7.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf13d564d310c156d1c8e53877baf2993fb3073b2fc9f69790ca6a732eb4bfea"}, - {file = "coverage-7.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5761c70c017c1b0d21b0815a920ffb94a670c8d5d409d9b38857874c21f70d7"}, - {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ff52d790c7e1628241ffbcaeb33e07d14b007b6eb00a19320c7b8a7024c040"}, - {file = "coverage-7.8.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d39fc4817fd67b3915256af5dda75fd4ee10621a3d484524487e33416c6f3543"}, - {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b44674870709017e4b4036e3d0d6c17f06a0e6d4436422e0ad29b882c40697d2"}, - {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f99eb72bf27cbb167b636eb1726f590c00e1ad375002230607a844d9e9a2318"}, - {file = "coverage-7.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b571bf5341ba8c6bc02e0baeaf3b061ab993bf372d982ae509807e7f112554e9"}, - {file = "coverage-7.8.0-cp311-cp311-win32.whl", hash = "sha256:e75a2ad7b647fd8046d58c3132d7eaf31b12d8a53c0e4b21fa9c4d23d6ee6d3c"}, - {file = "coverage-7.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:3043ba1c88b2139126fc72cb48574b90e2e0546d4c78b5299317f61b7f718b78"}, - {file = "coverage-7.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bbb5cc845a0292e0c520656d19d7ce40e18d0e19b22cb3e0409135a575bf79fc"}, - {file = "coverage-7.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4dfd9a93db9e78666d178d4f08a5408aa3f2474ad4d0e0378ed5f2ef71640cb6"}, - {file = "coverage-7.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f017a61399f13aa6d1039f75cd467be388d157cd81f1a119b9d9a68ba6f2830d"}, - {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0915742f4c82208ebf47a2b154a5334155ed9ef9fe6190674b8a46c2fb89cb05"}, - {file = "coverage-7.8.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a40fcf208e021eb14b0fac6bdb045c0e0cab53105f93ba0d03fd934c956143a"}, - {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a1f406a8e0995d654b2ad87c62caf6befa767885301f3b8f6f73e6f3c31ec3a6"}, - {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:77af0f6447a582fdc7de5e06fa3757a3ef87769fbb0fdbdeba78c23049140a47"}, - {file = "coverage-7.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f2d32f95922927186c6dbc8bc60df0d186b6edb828d299ab10898ef3f40052fe"}, - {file = "coverage-7.8.0-cp312-cp312-win32.whl", hash = "sha256:769773614e676f9d8e8a0980dd7740f09a6ea386d0f383db6821df07d0f08545"}, - {file = "coverage-7.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:e5d2b9be5b0693cf21eb4ce0ec8d211efb43966f6657807f6859aab3814f946b"}, - {file = "coverage-7.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5ac46d0c2dd5820ce93943a501ac5f6548ea81594777ca585bf002aa8854cacd"}, - {file = "coverage-7.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:771eb7587a0563ca5bb6f622b9ed7f9d07bd08900f7589b4febff05f469bea00"}, - {file = "coverage-7.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42421e04069fb2cbcbca5a696c4050b84a43b05392679d4068acbe65449b5c64"}, - {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:554fec1199d93ab30adaa751db68acec2b41c5602ac944bb19187cb9a41a8067"}, - {file = "coverage-7.8.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5aaeb00761f985007b38cf463b1d160a14a22c34eb3f6a39d9ad6fc27cb73008"}, - {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:581a40c7b94921fffd6457ffe532259813fc68eb2bdda60fa8cc343414ce3733"}, - {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f319bae0321bc838e205bf9e5bc28f0a3165f30c203b610f17ab5552cff90323"}, - {file = "coverage-7.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:04bfec25a8ef1c5f41f5e7e5c842f6b615599ca8ba8391ec33a9290d9d2db3a3"}, - {file = "coverage-7.8.0-cp313-cp313-win32.whl", hash = "sha256:dd19608788b50eed889e13a5d71d832edc34fc9dfce606f66e8f9f917eef910d"}, - {file = "coverage-7.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:a9abbccd778d98e9c7e85038e35e91e67f5b520776781d9a1e2ee9d400869487"}, - {file = "coverage-7.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:18c5ae6d061ad5b3e7eef4363fb27a0576012a7447af48be6c75b88494c6cf25"}, - {file = "coverage-7.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:95aa6ae391a22bbbce1b77ddac846c98c5473de0372ba5c463480043a07bff42"}, - {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e013b07ba1c748dacc2a80e69a46286ff145935f260eb8c72df7185bf048f502"}, - {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d766a4f0e5aa1ba056ec3496243150698dc0481902e2b8559314368717be82b1"}, - {file = "coverage-7.8.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad80e6b4a0c3cb6f10f29ae4c60e991f424e6b14219d46f1e7d442b938ee68a4"}, - {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b87eb6fc9e1bb8f98892a2458781348fa37e6925f35bb6ceb9d4afd54ba36c73"}, - {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d1ba00ae33be84066cfbe7361d4e04dec78445b2b88bdb734d0d1cbab916025a"}, - {file = "coverage-7.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f3c38e4e5ccbdc9198aecc766cedbb134b2d89bf64533973678dfcf07effd883"}, - {file = "coverage-7.8.0-cp313-cp313t-win32.whl", hash = "sha256:379fe315e206b14e21db5240f89dc0774bdd3e25c3c58c2c733c99eca96f1ada"}, - {file = "coverage-7.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2e4b6b87bb0c846a9315e3ab4be2d52fac905100565f4b92f02c445c8799e257"}, - {file = "coverage-7.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa260de59dfb143af06dcf30c2be0b200bed2a73737a8a59248fcb9fa601ef0f"}, - {file = "coverage-7.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:96121edfa4c2dfdda409877ea8608dd01de816a4dc4a0523356067b305e4e17a"}, - {file = "coverage-7.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8af63b9afa1031c0ef05b217faa598f3069148eeee6bb24b79da9012423b82"}, - {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89b1f4af0d4afe495cd4787a68e00f30f1d15939f550e869de90a86efa7e0814"}, - {file = "coverage-7.8.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ec0be97723ae72d63d3aa41961a0b9a6f5a53ff599813c324548d18e3b9e8c"}, - {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:8a1d96e780bdb2d0cbb297325711701f7c0b6f89199a57f2049e90064c29f6bd"}, - {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f1d8a2a57b47142b10374902777e798784abf400a004b14f1b0b9eaf1e528ba4"}, - {file = "coverage-7.8.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:cf60dd2696b457b710dd40bf17ad269d5f5457b96442f7f85722bdb16fa6c899"}, - {file = "coverage-7.8.0-cp39-cp39-win32.whl", hash = "sha256:be945402e03de47ba1872cd5236395e0f4ad635526185a930735f66710e1bd3f"}, - {file = "coverage-7.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:90e7fbc6216ecaffa5a880cdc9c77b7418c1dcb166166b78dbc630d07f278cc3"}, - {file = "coverage-7.8.0-pp39.pp310.pp311-none-any.whl", hash = "sha256:b8194fb8e50d556d5849753de991d390c5a1edeeba50f68e3a9253fbd8bf8ccd"}, - {file = "coverage-7.8.0-py3-none-any.whl", hash = "sha256:dbf364b4c5e7bae9250528167dfe40219b62e2d573c854d74be213e1e52069f7"}, - {file = "coverage-7.8.0.tar.gz", hash = "sha256:7a3d62b3b03b4b6fd41a085f3574874cf946cb4604d2b4d3e8dca8cd570ca501"}, + {file = "coverage-7.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7af3990490982fbd2437156c69edbe82b7edf99bc60302cceeeaf79afb886b8"}, + {file = "coverage-7.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5757a7b25fe48040fa120ba6597f5f885b01e323e0d13fe21ff95a70c0f76b7"}, + {file = "coverage-7.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8f105631835fdf191c971c4da93d27e732e028d73ecaa1a88f458d497d026cf"}, + {file = "coverage-7.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:21645788c5c2afa3df2d4b607638d86207b84cb495503b71e80e16b4c6b44e80"}, + {file = "coverage-7.8.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e93f36a5c9d995f40e9c4cd9bbabd83fd78705792fa250980256c93accd07bb6"}, + {file = "coverage-7.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d591f2ddad432b794f77dc1e94334a80015a3fc7fa07fd6aed8f40362083be5b"}, + {file = "coverage-7.8.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:be2b1a455b3ecfee20638289bb091a95216887d44924a41c28a601efac0916e8"}, + {file = "coverage-7.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:061a3bf679dc38fe34d3822f10a9977d548de86b440010beb1e3b44ba93d20f7"}, + {file = "coverage-7.8.1-cp310-cp310-win32.whl", hash = "sha256:12950b6373dc9dfe1ce22a8506ec29c82bfc5b38146ced0a222f38cf5d99a56d"}, + {file = "coverage-7.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:11e5ea0acd8cc5d23030c34dfb2eb6638ad886328df18cc69f8eefab73d1ece5"}, + {file = "coverage-7.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc6bebc15c3b275174c66cf4e1c949a94c5c2a3edaa2f193a1225548c52c771"}, + {file = "coverage-7.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a6c35afd5b912101fabf42975d92d750cfce33c571508a82ff334a133c40d5"}, + {file = "coverage-7.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b37729ba34c116a3b2b6fb99df5c37a4ca40e96f430070488fd7a1077ad44907"}, + {file = "coverage-7.8.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6424c716f4c38ff8f62b602e6b94cde478dadda542a1cb3fe2fe2520cc2aae3"}, + {file = "coverage-7.8.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bcfafb2809cd01be8ffe5f962e01b0fbe4cc1d74513434c52ff2dd05b86d492"}, + {file = "coverage-7.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e3f65da9701648d226b6b24ded3e2528b72075e48d7540968cd857c3bd4c5321"}, + {file = "coverage-7.8.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:173e16969f990688aae4b4487717c44330bc57fd8b61a6216ce8eeb827eb5c0d"}, + {file = "coverage-7.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3763b9a4bc128f72da5dcfd7fcc7c7d6644ed28e8f2db473ce1ef0dd37a43fa9"}, + {file = "coverage-7.8.1-cp311-cp311-win32.whl", hash = "sha256:d074380f587360d2500f3b065232c67ae248aaf739267807adbcd29b88bdf864"}, + {file = "coverage-7.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:cd21de85aa0e247b79c6c41f8b5541b54285550f2da6a9448d82b53234d3611b"}, + {file = "coverage-7.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d8f844e837374a9497e11722d9eb9dfeb33b1b5d31136786c39a4c1a3073c6d"}, + {file = "coverage-7.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9cd54a762667c32112df5d6f059c5d61fa532ee06460948cc5bcbf60c502f5c9"}, + {file = "coverage-7.8.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:958b513e23286178b513a6b4d975fe9e7cddbcea6e5ebe8d836e4ef067577154"}, + {file = "coverage-7.8.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b31756ea647b6ef53190f6b708ad0c4c2ea879bc17799ba5b0699eee59ecf7b"}, + {file = "coverage-7.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccad4e29ac1b6f75bfeedb2cac4860fe5bd9e0a2f04c3e3218f661fa389ab101"}, + {file = "coverage-7.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:452f3831c64f5f50260e18a89e613594590d6ceac5206a9b7d76ba43586b01b3"}, + {file = "coverage-7.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9296df6a33b8539cd753765eb5b47308602263a14b124a099cbcf5f770d7cf90"}, + {file = "coverage-7.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d52d79dfd3b410b153b6d65b0e3afe834eca2b969377f55ad73c67156d35af0d"}, + {file = "coverage-7.8.1-cp312-cp312-win32.whl", hash = "sha256:ebdf212e1ed85af63fa1a76d556c0a3c7b34348ffba6e145a64b15f003ad0a2b"}, + {file = "coverage-7.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:c04a7903644ccea8fa07c3e76db43ca31c8d453f93c5c94c0f9b82efca225543"}, + {file = "coverage-7.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd5c305faa2e69334a53061b3168987847dadc2449bab95735242a9bde92fde8"}, + {file = "coverage-7.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:af6b8cdf0857fd4e6460dd6639c37c3f82163127f6112c1942b5e6a52a477676"}, + {file = "coverage-7.8.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e233a56bbf99e4cb134c4f8e63b16c77714e3987daf2c5aa10c3ba8c4232d730"}, + {file = "coverage-7.8.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dabc70012fd7b58a8040a7bc1b5f71fd0e62e2138aefdd8367d3d24bf82c349"}, + {file = "coverage-7.8.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1f8e96455907496b3e4ea16f63bb578da31e17d2805278b193525e7714f17f2"}, + {file = "coverage-7.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0034ceec8e91fdaf77350901cc48f47efd00f23c220a3f9fc1187774ddf307cb"}, + {file = "coverage-7.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82db9344a07dd9106796b9fe8805425633146a7ea7fed5ed07c65a64d0bb79e1"}, + {file = "coverage-7.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9772c9e266b2ca4999180c12b90c8efb4c5c9ad3e55f301d78bc579af6467ad9"}, + {file = "coverage-7.8.1-cp313-cp313-win32.whl", hash = "sha256:6f24a1e2c373a77afae21bc512466a91e31251685c271c5309ee3e557f6e3e03"}, + {file = "coverage-7.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:76a4e1d62505a21971968be61ae17cbdc5e0c483265a37f7ddbbc050f9c0b8ec"}, + {file = "coverage-7.8.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:35dd5d405a1d378c39f3f30f628a25b0b99f1b8e5bdd78275df2e7b0404892d7"}, + {file = "coverage-7.8.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:87b86a87f8de2e1bd0bcd45faf1b1edf54f988c8857157300e0336efcfb8ede6"}, + {file = "coverage-7.8.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce4553a573edb363d5db12be1c044826878bec039159d6d4eafe826ef773396d"}, + {file = "coverage-7.8.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db181a1896e0bad75b3bf4916c49fd3cf6751f9cc203fe0e0ecbee1fc43590fa"}, + {file = "coverage-7.8.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ce2606a171f9cf7c15a77ca61f979ffc0e0d92cd2fb18767cead58c1d19f58e"}, + {file = "coverage-7.8.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4fc4f7cff2495d6d112353c33a439230a6de0b7cd0c2578f1e8d75326f63d783"}, + {file = "coverage-7.8.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ff619c58322d9d6df0a859dc76c3532d7bdbc125cb040f7cd642141446b4f654"}, + {file = "coverage-7.8.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0d6290a466a6f3fadf6add2dd4ec11deba4e1a6e3db2dd284edd497aadf802f"}, + {file = "coverage-7.8.1-cp313-cp313t-win32.whl", hash = "sha256:e4e893c7f7fb12271a667d5c1876710fae06d7580343afdb5f3fc4488b73209e"}, + {file = "coverage-7.8.1-cp313-cp313t-win_amd64.whl", hash = "sha256:41d142eefbc0bb3be160a77b2c0fbec76f345387676265052e224eb6c67b7af3"}, + {file = "coverage-7.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5102e17b81158de17d4b5bc363fcffd15231a38ef3f50b8e6fa01f0c6911194"}, + {file = "coverage-7.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3bd8e3753257e95e94f38c058627aba1581d51f674e3badf226283b2bdb8f8ca"}, + {file = "coverage-7.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d616b5a543c7d4deffa25eb8d8ae3d0d95097f08ac8b131600bb7fbf967ea0e2"}, + {file = "coverage-7.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7a95b0dce364535a63fde0ec1b1ca36400037175d3b62ce04d85dbca5e33832"}, + {file = "coverage-7.8.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f82c1a1c1897d2293cb6c50f20fe8a9ea2add1a228eff479380917a1fe7bbb68"}, + {file = "coverage-7.8.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:62a13b372b65fa6e11685df9ca924bed23bab1d0f277f9b67be7536f253aaf17"}, + {file = "coverage-7.8.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe4877c24711458f7990392181be30166cc3ae72158036ecb48a73c30c99fb6f"}, + {file = "coverage-7.8.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ae5e557aa92565d72f6d3196e878e7cbd6a6380e02a15eafe0af781bd767c10d"}, + {file = "coverage-7.8.1-cp39-cp39-win32.whl", hash = "sha256:87284f272746e31919302ab6211b16b41135109822c498f6e7b40a2f828e7836"}, + {file = "coverage-7.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:07fff2f2ce465fae27447432d39ce733476fbf8478de51fb4034c201e0c5da6d"}, + {file = "coverage-7.8.1-pp39.pp310.pp311-none-any.whl", hash = "sha256:adafe9d71a940927dd3ad8d487f521f11277f133568b7da622666ebd08923191"}, + {file = "coverage-7.8.1-py3-none-any.whl", hash = "sha256:e54b80885b0e61d346accc5709daf8762471a452345521cc9281604a907162c2"}, + {file = "coverage-7.8.1.tar.gz", hash = "sha256:d41d4da5f2871b1782c6b74948d2d37aac3a5b39b43a6ba31d736b97a02ae1f1"}, ] [package.extras] @@ -2351,8 +2351,8 @@ web3 = "==6.1.0" [package.source] type = "git" url = "https://github.com/valory-xyz/olas-operate-middleware.git" -reference = "c737adcf63bc89d21141a505fcdce53fead4df65" -resolved_reference = "c737adcf63bc89d21141a505fcdce53fead4df65" +reference = "920957b1871a533a3a63f1162d9c6d10625226a8" +resolved_reference = "920957b1871a533a3a63f1162d9c6d10625226a8" [[package]] name = "open-aea" @@ -3651,13 +3651,13 @@ files = [ [[package]] name = "typing-inspection" -version = "0.4.0" +version = "0.4.1" description = "Runtime typing introspection tools" optional = false python-versions = ">=3.9" files = [ - {file = "typing_inspection-0.4.0-py3-none-any.whl", hash = "sha256:50e72559fcd2a6367a19f7a7e610e6afcb9fac940c650290eed893d61386832f"}, - {file = "typing_inspection-0.4.0.tar.gz", hash = "sha256:9765c87de36671694a67904bf2c96e395be9c6439bb6c87b5142569dcdd65122"}, + {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, + {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, ] [package.dependencies] @@ -4058,4 +4058,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "a553ded59c6fdf572c007f7c333024d6a53d2625f1af3cd64be051ac9939374b" +content-hash = "ee0d3ab758d5e2dfc4e0e984b7064f301bb3dd800b9a82a39358d4375a1e3c8e" diff --git a/pyproject.toml b/pyproject.toml index 6f095a541..bf64ec1b3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ include = [] [tool.poetry.dependencies] python = ">=3.9,<3.12" -olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "c737adcf63bc89d21141a505fcdce53fead4df65"} +olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "920957b1871a533a3a63f1162d9c6d10625226a8"} [build-system] requires = ["poetry-core"] From 7ada98c64c62cda0789d5018ba19e67d9db571ae Mon Sep 17 00:00:00 2001 From: Mohan Date: Fri, 23 May 2025 19:56:40 +0530 Subject: [PATCH 11/44] chore: update staging-ea with staging (#928) * feat: staging to main (#920) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) * feat: modius hash update (#916) * fix: update hash for Modius service template * fix: update hash for Modius service template * fix: update hash for Modius service template * feat: staging to main (#913) (#919) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts --------- * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- * release: 0.2.0-rc270 * chore: update middleware --------- * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) --------- Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory * fix: update hash for Trader Agent service template (#921) * fix: update comment for Trader Agent name uniqueness * feat: FE implementation of New Agents.fun setup integration (#907) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware * feat: memeooorr consolidate form (#904) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * feat: memeooorr add new fields to form (#905) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * refactor: remove Twitter validation logic and associated types from Memeooorr agent form * chore: add TODO comments for product clarification in YourAgentCannotSignIn and AgentTitle components * feat: refactor Memeooorr agent form and related components to integrate new API keys and remove deprecated fields * feat: update Memeooorr agent form and setup components for improved API token handling and styling * feat: refactor Memeooorr agent form and validation logic to enhance API token handling and streamline component imports * feat: update Memeooorr agent form and types to include XCredentialsKeys and enhance service description handling * feat: remove Twitter login validation and related dependencies from the application * feat: remove YourAgentCannotSignIn component and related imports from AlertSections * feat: add X username field to Memeooorr agent form and update related components * feat: update Memeooorr agent form and related components to include X username handling * feat: Update agent setup and show alert (#908) * feat: add UpdateAgentConfiguration component to alert sections * feat: remove healthcheck alert state and related logic from SharedProvider * feat: implement isMemeooorrFieldUpdateCompleted check for agent deployment and alert visibility * feat: add MemeooorrUpdateSetup component and update routing in UpdateAgentPage * feat: update loading text style to fit content and add fit-content class * feat: add clarification comments for Memeooorr agent configuration requirements * chore: bump middleware (#909) Signed-off-by: OjusWiZard * feat: update service template hash and version for Memeooorr agent * fix: add `tweepy` dependency Signed-off-by: OjusWiZard * fix: show alert on agent settings (#911) * feat: add showTokensRequiredMessage prop to XAccountApiTokens and display alert * feat: update MemeooorrAgentForm to use agentFormType prop for variant handling * fix: update hash and service version for AGENTS_FUN_COMMON_TEMPLATE --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * fix: update version to 0.2.0-rc173 in package.json and pyproject.toml --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * fix: update service template hashes and version for Trader and Optimus agents (#926) --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard --- frontend/constants/serviceTemplates.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 5e3933e04..da50b2442 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -10,11 +10,11 @@ import { parseEther, parseUnits } from '@/utils/numberFormatters'; export const PREDICT_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.PredictTrader, // TODO: remove if causes errors on middleware name: 'Trader Agent', // should be unique across all services and not be updated - hash: 'bafybeie2p3lw5iaj44yymwxjdjqpdx6jxgfz4vmq6gpt3e63yipjujaqnu', + hash: 'bafybeihe7r2a2vnbbqrzczlzjhhmzypxbre3gobupc65w4ea266hmk5efu', description: 'Trader agent for omen prediction markets', image: 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', - service_version: 'v0.25.0', + service_version: 'v0.25.5', home_chain: MiddlewareChain.GNOSIS, configurations: { [MiddlewareChain.GNOSIS]: { @@ -265,7 +265,7 @@ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = { export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Modius, name: 'Optimus', // Should be unique across all services and not be updated - hash: 'bafybeicjz2hqbptzoutvkiht6vxt255ibfmkg5spcypuavzpvgx3s4yiuq', + hash: 'bafybeicxflz5lzklgc522zytvwi4rgycghdqdmzgkxojnjatommr7qvqfm', description: 'Optimus', image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', From 54fb16aae636ed7f076dd7dbf45d075d4f84279b Mon Sep 17 00:00:00 2001 From: Mohan Date: Tue, 27 May 2025 17:46:37 +0530 Subject: [PATCH 12/44] feat: optimus more features (#902) * fix: enable agent-settings feature for Optimus agent * fix: update backup-via-safe feature flag to enabled --- .../index.tsx => AddBackupWalletViaSafePage.tsx} | 12 ++++++------ frontend/hooks/useFeatureFlag.ts | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) rename frontend/components/Pages/{AddBackupWalletViaSafePage/index.tsx => AddBackupWalletViaSafePage.tsx} (88%) diff --git a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx b/frontend/components/Pages/AddBackupWalletViaSafePage.tsx similarity index 88% rename from frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx rename to frontend/components/Pages/AddBackupWalletViaSafePage.tsx index 59bb97226..856994880 100644 --- a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx +++ b/frontend/components/Pages/AddBackupWalletViaSafePage.tsx @@ -7,7 +7,7 @@ import { DISCORD_TICKET_URL } from '@/constants/urls'; import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; -import { GoToMainPageButton } from '../GoToMainPageButton'; +import { GoToMainPageButton } from './GoToMainPageButton'; const { Text } = Typography; @@ -24,18 +24,17 @@ const safeChainPrefix = { }; export const AddBackupWalletViaSafePage = () => { + const { masterSafes } = useMasterWalletContext(); const { selectedAgentConfig: { evmHomeChainId }, } = useServices(); - const { masterSafes } = useMasterWalletContext(); - const masterSafe = masterSafes?.find( ({ evmChainId: chainId }) => evmHomeChainId === chainId, ); const safePrefix = - masterSafe?.evmChainId && safeChainPrefix[masterSafe?.evmChainId]; + masterSafe?.evmChainId && safeChainPrefix[masterSafe.evmChainId]; return ( { Manually add backup wallet via Safe interface: - {!masterSafe?.address && } - {masterSafe?.address && ( + {masterSafe?.address ? ( Open Safe interface {UNICODE_SYMBOLS.EXTERNAL_LINK} + ) : ( + )} diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index 8d5281c6d..ee51375da 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -81,8 +81,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'staking-contract-section': true, 'low-funds': false, 'agent-activity': true, - 'backup-via-safe': false, // temporarily hidden until mode is available on safe https://app.safe.global/new-safe/create - 'agent-settings': false, + 'backup-via-safe': true, + 'agent-settings': true, }, }); From cdc96e96b745c0c11c210842a078f02fea4fb54a Mon Sep 17 00:00:00 2001 From: Mohan Date: Tue, 27 May 2025 19:06:36 +0530 Subject: [PATCH 13/44] chore: conflict fixes (#935) --- .github/workflows/release_win.yml | 2 +- .github/workflows/release_win_dev.yml | 2 +- Makefile | 8 +- electron/constants/index.js | 1 + electron/main.js | 49 +- electron/preload.js | 2 - electron/public/chains/base-chain.png | Bin 0 -> 2894 bytes electron/public/chains/ethereum-chain.png | Bin 0 -> 2769 bytes electron/public/chains/gnosis-chain.png | Bin 0 -> 3868 bytes electron/public/chains/mode-chain.png | Bin 0 -> 2382 bytes frontend/client/types.ts | 24 +- frontend/components/AgentActivity/index.tsx | 2 +- .../MemeooorrAgentForm/FireworksApiField.tsx | 2 +- .../MemeooorrAgentForm/MemeooorrAgentForm.tsx | 224 +++ .../AgentForms/MemeooorrAgentForm/index.ts | 2 + .../AgentForms/MemeooorrAgentForm/types.ts | 20 + .../MemeooorrAgentForm/useMemeFormValidate.ts | 53 + .../common}/InvalidGeminiApiCredentials.tsx | 0 .../shared => AgentForms/common}/formUtils.ts | 14 + .../shared => AgentForms/common}/labels.tsx | 0 .../AgentForms/common/validations.ts | 20 + frontend/components/ExportLogsButton.tsx | 63 + .../header/AgentButton/AgentButton.tsx | 6 +- .../AgentButton/AgentNotRunningButton.tsx | 7 + .../MainPage/sections/AddFundsSection.tsx | 156 +- .../UpdateAgentConfiguration.tsx | 45 + .../AlertSections/YourAgentCannotSignIn.tsx | 92 - .../MainPage/sections/AlertSections/index.tsx | 4 +- .../RewardsSection/NotifyRewardsModal.tsx | 4 +- .../sections/RewardsSection/RewardsStreak.tsx | 4 +- .../WhatAreStakingContracts.tsx | 39 - .../components/ManageStakingPage/index.tsx | 43 +- frontend/components/NumberInput.tsx | 39 + .../components/Pages/HelpAndSupportPage.tsx | 74 + .../Pages/HelpAndSupportPage/index.tsx | 127 -- .../SetupPage/AgentIntroduction/constants.ts | 13 +- .../BridgeInProgress/BridgeInProgress.tsx | 261 +++ .../BridgeInProgress/useBridgingSteps.ts | 180 ++ .../useMasterSafeCreationAndTransfer.ts | 55 + .../BridgeInProgress/useRetryBridge.ts | 35 + .../SetupBridgeOnboarding/BridgeOnEvm.tsx | 67 + .../SetupBridgeOnboarding.tsx | 94 + .../Create/SetupBridgeOnboarding/types.ts | 1 + .../SetupPage/Create/SetupCreateHeader.tsx | 13 +- .../SetupPage/Create/SetupCreateSafe.tsx | 43 +- .../SetupPage/Create/SetupEoaFunding.tsx | 261 ++- .../SetupPage/Create/SetupPassword.tsx | 5 +- .../components/SetupPage/SetupRestore.tsx | 6 +- .../MemeooorrAgentForm/MemeooorrAgentForm.tsx | 273 --- .../MemeooorrAgentForm/useMemeFormValidate.ts | 87 - .../SetupYourAgent/MemeooorrAgentSetup.tsx | 101 + .../ModiusAgentForm/ModiusAgentForm.tsx | 8 +- .../ModiusAgentForm/useModiusFormValidate.ts | 5 +- .../OptimusAgentForm/OptimusAgentForm.tsx | 8 +- .../useOptimusFormValidate.ts | 5 +- .../SetupYourAgent/SetupYourAgent.tsx | 8 +- .../SetupPage/SetupYourAgent/shared/utils.ts | 14 - .../SetupYourAgent/shared/validations.ts | 70 - frontend/components/SetupPage/index.tsx | 15 +- .../UpdateAgentPage/MemeooorrUpdatePage.tsx | 250 --- .../UpdateAgentPage/MemeooorrUpdateSetup.tsx | 90 + .../UpdateAgentPage/ModiusUpdateForm.tsx | 10 +- .../UpdateAgentPage/OptimusUpdateForm.tsx | 8 +- .../context/UpdateAgentProvider.tsx | 35 +- frontend/components/UpdateAgentPage/index.tsx | 4 +- .../components/YourWalletPage/AgentTitle.tsx | 9 +- .../bridge/AddFundsThroughBridge.tsx | 139 ++ .../components/bridge/BridgeTransferFlow.tsx | 83 + frontend/components/bridge/BridgingSteps.tsx | 240 +++ frontend/components/bridge/DepositAddress.tsx | 42 + .../components/bridge/DepositForBridging.tsx | 342 ++++ .../bridge/EstimatedCompletionTime.tsx | 61 + frontend/components/bridge/TokenDetails.tsx | 95 + frontend/components/bridge/types.ts | 1 + frontend/components/bridge/utils.ts | 216 +++ frontend/components/errors/ErrorComponent.tsx | 3 - frontend/components/styled/CardFlex.tsx | 34 +- frontend/components/styled/CardSection.tsx | 26 +- frontend/components/ui/iconStyles.ts | 6 + frontend/config/agents.ts | 5 +- frontend/config/tokens.ts | 25 + frontend/constants/address.ts | 5 + frontend/constants/colors.ts | 2 + frontend/constants/intervals.ts | 2 + frontend/constants/react-query-keys.ts | 8 + frontend/constants/serviceTemplates.ts | 42 +- frontend/constants/urls.ts | 6 +- .../BalancesAndRefillRequirementsProvider.tsx | 44 +- frontend/context/ElectronApiProvider.tsx | 12 - frontend/context/MasterWalletProvider.tsx | 31 +- .../context/SharedProvider/SharedProvider.tsx | 46 +- frontend/enums/Pages.ts | 1 + frontend/enums/SetupScreen.ts | 3 + frontend/hooks/useBackupSigner.ts | 15 + frontend/hooks/useBridgeRefillRequirements.ts | 37 + frontend/hooks/useFeatureFlag.ts | 10 + frontend/hooks/useLogs.ts | 18 +- frontend/hooks/usePageState.ts | 11 +- frontend/pages/index.tsx | 6 + frontend/public/chains/base-chain.png | Bin 0 -> 2894 bytes frontend/public/chains/ethereum-chain.png | Bin 0 -> 2769 bytes frontend/public/chains/gnosis-chain.png | Bin 0 -> 3868 bytes frontend/public/chains/mode-chain.png | Bin 0 -> 2382 bytes frontend/public/olas-icon.png | Bin 0 -> 35622 bytes frontend/public/setup-agent-modius-1.png | Bin 39232 -> 39891 bytes frontend/service/Bridge.ts | 65 + frontend/service/Wallet.ts | 11 +- frontend/styles/globals.scss | 75 +- frontend/theme/index.ts | 9 + frontend/types/Bridge.ts | 88 + frontend/types/Cookies.ts | 14 - frontend/types/Wallet.ts | 7 + frontend/utils/address.ts | 11 + frontend/utils/calculations.ts | 9 + frontend/utils/middlewareHelpers.ts | 23 + frontend/utils/numberFormatters.ts | 6 +- frontend/utils/service.ts | 28 +- frontend/utils/x.ts | 18 + package.json | 3 +- poetry.lock | 1624 +++++++++-------- pyproject.toml | 4 +- tests/__init__.py | 1 - tests/test_services_manage.py | 344 ---- tests/test_services_service.py | 360 ---- tests/test_wallet_master.py | 20 - yarn.lock | 180 +- 126 files changed, 4694 insertions(+), 2985 deletions(-) create mode 100644 electron/public/chains/base-chain.png create mode 100644 electron/public/chains/ethereum-chain.png create mode 100644 electron/public/chains/gnosis-chain.png create mode 100644 electron/public/chains/mode-chain.png rename frontend/components/{SetupPage/SetupYourAgent => AgentForms}/MemeooorrAgentForm/FireworksApiField.tsx (98%) create mode 100644 frontend/components/AgentForms/MemeooorrAgentForm/MemeooorrAgentForm.tsx create mode 100644 frontend/components/AgentForms/MemeooorrAgentForm/index.ts create mode 100644 frontend/components/AgentForms/MemeooorrAgentForm/types.ts create mode 100644 frontend/components/AgentForms/MemeooorrAgentForm/useMemeFormValidate.ts rename frontend/components/{SetupPage/SetupYourAgent/shared => AgentForms/common}/InvalidGeminiApiCredentials.tsx (100%) rename frontend/components/{SetupPage/SetupYourAgent/shared => AgentForms/common}/formUtils.ts (84%) rename frontend/components/{SetupPage/SetupYourAgent/shared => AgentForms/common}/labels.tsx (100%) create mode 100644 frontend/components/AgentForms/common/validations.ts create mode 100644 frontend/components/ExportLogsButton.tsx create mode 100644 frontend/components/MainPage/sections/AlertSections/UpdateAgentConfiguration.tsx delete mode 100644 frontend/components/MainPage/sections/AlertSections/YourAgentCannotSignIn.tsx delete mode 100644 frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx create mode 100644 frontend/components/NumberInput.tsx create mode 100644 frontend/components/Pages/HelpAndSupportPage.tsx delete mode 100644 frontend/components/Pages/HelpAndSupportPage/index.tsx create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useBridgingSteps.ts create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useMasterSafeCreationAndTransfer.ts create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useRetryBridge.ts create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/SetupBridgeOnboarding.tsx create mode 100644 frontend/components/SetupPage/Create/SetupBridgeOnboarding/types.ts delete mode 100644 frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/MemeooorrAgentForm.tsx delete mode 100644 frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/useMemeFormValidate.ts create mode 100644 frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentSetup.tsx delete mode 100644 frontend/components/SetupPage/SetupYourAgent/shared/utils.ts delete mode 100644 frontend/components/SetupPage/SetupYourAgent/shared/validations.ts delete mode 100644 frontend/components/UpdateAgentPage/MemeooorrUpdatePage.tsx create mode 100644 frontend/components/UpdateAgentPage/MemeooorrUpdateSetup.tsx create mode 100644 frontend/components/bridge/AddFundsThroughBridge.tsx create mode 100644 frontend/components/bridge/BridgeTransferFlow.tsx create mode 100644 frontend/components/bridge/BridgingSteps.tsx create mode 100644 frontend/components/bridge/DepositAddress.tsx create mode 100644 frontend/components/bridge/DepositForBridging.tsx create mode 100644 frontend/components/bridge/EstimatedCompletionTime.tsx create mode 100644 frontend/components/bridge/TokenDetails.tsx create mode 100644 frontend/components/bridge/types.ts create mode 100644 frontend/components/bridge/utils.ts delete mode 100644 frontend/components/errors/ErrorComponent.tsx create mode 100644 frontend/components/ui/iconStyles.ts create mode 100644 frontend/hooks/useBackupSigner.ts create mode 100644 frontend/hooks/useBridgeRefillRequirements.ts create mode 100644 frontend/public/chains/base-chain.png create mode 100644 frontend/public/chains/ethereum-chain.png create mode 100644 frontend/public/chains/gnosis-chain.png create mode 100644 frontend/public/chains/mode-chain.png create mode 100644 frontend/public/olas-icon.png create mode 100644 frontend/service/Bridge.ts create mode 100644 frontend/types/Bridge.ts delete mode 100644 frontend/types/Cookies.ts create mode 100644 frontend/types/Wallet.ts create mode 100644 frontend/utils/address.ts create mode 100644 frontend/utils/calculations.ts create mode 100644 frontend/utils/x.ts delete mode 100644 tests/__init__.py delete mode 100644 tests/test_services_manage.py delete mode 100644 tests/test_services_service.py delete mode 100644 tests/test_wallet_master.py diff --git a/.github/workflows/release_win.yml b/.github/workflows/release_win.yml index daae14d59..3ccaf18fa 100644 --- a/.github/workflows/release_win.yml +++ b/.github/workflows/release_win.yml @@ -50,7 +50,7 @@ jobs: - name: Install and configure Poetry uses: snok/install-poetry@v1 with: - version: "1.8.3" + version: "2.1.1" virtualenvs-create: true virtualenvs-in-project: false virtualenvs-path: ~/my-custom-path diff --git a/.github/workflows/release_win_dev.yml b/.github/workflows/release_win_dev.yml index 20ae88d9e..e38f36503 100644 --- a/.github/workflows/release_win_dev.yml +++ b/.github/workflows/release_win_dev.yml @@ -50,7 +50,7 @@ jobs: - name: Install and configure Poetry uses: snok/install-poetry@v1 with: - version: "1.8.3" + version: "2.1.1" virtualenvs-create: true virtualenvs-in-project: false virtualenvs-path: ~/my-custom-path diff --git a/Makefile b/Makefile index eacc5f14a..726e52cf2 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ endef ./dist/aea_win.exe: ./electron/bins/ ./trader/ mkdir -p dist - cd meme-ooorr && poetry lock --no-update && poetry install && poetry add backports.tarfile gql==3.5.0 hypothesis==6.21.6 pycoingecko==3.2.0 numpy==2.2.0 pandas>=2.2.3 pyfolio==0.9.2 scipy==1.14.1 && poetry run pyinstaller --collect-all gql --collect-all hypothesis --collect-all pycoingecko --collect-all scipy --hidden-import numpy --collect-all pandas --collect-all pyfolio --collect-all twitter_text --collect-all google.generativeai --collect-all peewee --collect-data eth_account --collect-all aea --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots --hidden-import grpc --hidden-import openapi_core --collect-all google.protobuf --collect-all openapi_core --collect-all openapi_spec_validator --collect-all asn1crypto --hidden-import py_ecc --hidden-import pytz --collect-all twikit --collect-all twitter_text_parser --collect-all textblob --collect-all backports.tarfile --collect-all js2py --onefile pyinstaller/memeooorr_bin.py --name trader_win + cd meme-ooorr && poetry lock && poetry install && poetry add backports.tarfile gql==3.5.0 hypothesis==6.21.6 pycoingecko==3.2.0 numpy==2.2.0 pandas>=2.2.3 pyfolio==0.9.2 scipy==1.14.1 && poetry run pyinstaller --collect-all gql --collect-all hypothesis --collect-all pycoingecko --collect-all scipy --hidden-import numpy --collect-all pandas --collect-all pyfolio --collect-all twitter_text --collect-all google.generativeai --collect-all peewee --collect-data eth_account --collect-all aea --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots --hidden-import grpc --hidden-import openapi_core --collect-all google.protobuf --collect-all openapi_core --collect-all openapi_spec_validator --collect-all asn1crypto --hidden-import py_ecc --hidden-import pytz --collect-all twikit --collect-all tweepy --collect-all twitter_text_parser --collect-all textblob --collect-all backports.tarfile --collect-all js2py --onefile pyinstaller/memeooorr_bin.py --name trader_win ls -l meme-ooorr/dist cp -f meme-ooorr/dist/trader_win.exe ./dist/aea_win.exe cp -f meme-ooorr/dist/trader_win.exe ./electron/bins/aea_win.exe @@ -23,21 +23,21 @@ endef ./dist/aea_bin: ./trader/ mkdir -p dist - cd meme-ooorr && poetry lock --no-update && poetry install && poetry add backports.tarfile gql==3.5.0 hypothesis==6.21.6 pycoingecko==3.2.0 numpy==2.2.0 pandas>=2.2.3 pyfolio==0.9.2 scipy==1.14.1 && poetry run pyinstaller --collect-all gql --collect-all hypothesis --collect-all pycoingecko --collect-all scipy --hidden-import numpy --collect-all pandas --collect-all pyfolio --collect-all twitter_text --collect-all google.generativeai --collect-all peewee --collect-data eth_account --collect-all aea --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots --hidden-import grpc --hidden-import openapi_core --collect-all google.protobuf --collect-all openapi_core --collect-all openapi_spec_validator --collect-all asn1crypto --hidden-import py_ecc --hidden-import pytz --collect-all twikit --collect-all twitter_text_parser --collect-all textblob --collect-all backports.tarfile --collect-all js2py --onefile pyinstaller/memeooorr_bin.py --name trader_bin + cd meme-ooorr && poetry lock --no-update && poetry install && poetry add backports.tarfile gql==3.5.0 hypothesis==6.21.6 pycoingecko==3.2.0 numpy==2.2.0 pandas>=2.2.3 pyfolio==0.9.2 scipy==1.14.1 && poetry run pyinstaller --collect-all gql --collect-all hypothesis --collect-all pycoingecko --collect-all scipy --hidden-import numpy --collect-all pandas --collect-all pyfolio --collect-all twitter_text --collect-all google.generativeai --collect-all peewee --collect-data eth_account --collect-all aea --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots --hidden-import grpc --hidden-import openapi_core --collect-all google.protobuf --collect-all openapi_core --collect-all openapi_spec_validator --collect-all asn1crypto --hidden-import py_ecc --hidden-import pytz --collect-all twikit --collect-all tweepy --collect-all twitter_text_parser --collect-all textblob --collect-all backports.tarfile --collect-all js2py --onefile pyinstaller/memeooorr_bin.py --name trader_bin cp -f meme-ooorr/dist/trader_bin ./dist/aea_bin pwd ./dist/tendermint_win.exe: ./electron/bins/ ./operate/ pwd - poetry install && poetry run pyinstaller operate/tendermint.py --onefile --name tendermint_win + poetry install --no-root && poetry run pyinstaller operate/tendermint.py --onefile --name tendermint_win ls -l dist cp dist/tendermint_win.exe ./electron/bins/tendermint_win.exe ./dist/pearl_win.exe: ./operate/ ./dist/aea_win.exe ./dist/tendermint_win.exe pwd - poetry install && poetry run pyinstaller --collect-data eth_account --collect-all aea --collect-all coincurve --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots operate/pearl.py --onefile --name pearl_win + poetry install --no-root && poetry run pyinstaller --collect-data eth_account --collect-all aea --collect-all coincurve --collect-all autonomy --collect-all operate --collect-all aea_ledger_ethereum --collect-all aea_ledger_cosmos --collect-all aea_ledger_ethereum_flashbots --hidden-import aea_ledger_ethereum --hidden-import aea_ledger_cosmos --hidden-import aea_ledger_ethereum_flashbots operate/pearl.py --onefile --name pearl_win ./electron/bins/: diff --git a/electron/constants/index.js b/electron/constants/index.js index 0d3c16db7..ccb2b7d58 100644 --- a/electron/constants/index.js +++ b/electron/constants/index.js @@ -29,6 +29,7 @@ const paths = { electronLogFile: path.join(dotOperateDirectory, 'electron.log'), nextLogFile: path.join(dotOperateDirectory, 'next.log'), osPearlTempDir: path.join(os.tmpdir(), 'pearl'), + bridgeDirectory: path.join(dotOperateDirectory, 'bridge'), }; // Publish options diff --git a/electron/main.js b/electron/main.js index 8418d1430..93dc22d92 100644 --- a/electron/main.js +++ b/electron/main.js @@ -25,7 +25,6 @@ const { setupStoreIpc } = require('./store'); const { logger } = require('./logger'); const { isDev } = require('./constants'); const { PearlTray } = require('./components/PearlTray'); -const { Scraper } = require('agent-twitter-client'); const { checkUrl } = require('./utils'); // Validates environment variables required for Pearl @@ -177,8 +176,7 @@ async function beforeQuit(event) { ); logger.electron('Killed backend server by shutdown endpoint!'); logger.electron( - 'Killed backend server by shutdown endpoint! result:' + - JSON.stringify(result), + `Killed backend server by shutdown endpoint! result: ${JSON.stringify(result)}`, ); } catch (err) { logger.electron('Backend stopped with error!'); @@ -321,30 +319,6 @@ const createMainWindow = async () => { ipcMain.handle('app-version', () => app.getVersion()); - // Handle twitter login - ipcMain.handle('validate-twitter-login', async (_event, credentials) => { - const { username, password, email } = credentials; - - logger.electron('Validating X login:', { username }); - if (!username || !password || !email) { - logger.electron('Missing credentials for X login'); - return { success: false, error: 'Missing credentials' }; - } - - try { - const scraper = new Scraper(); - - await scraper.login(username, password, email); - const cookies = await scraper.getCookies(); - logger.electron('X login successful!'); - return { success: true, cookies }; - } catch (error) { - logger.electron('X login failed:', error); - console.error('X login error:', error); - return { success: false, error: error.message }; - } - }); - // Get the agent's current state ipcMain.handle('health-check', async (_event) => { try { @@ -762,7 +736,9 @@ function sanitizeLogs({ return sanitizedLogsFilePath; } -// EXPORT LOGS +/** + * Exports logs by creating a zip file containing sanitized logs and other relevant data. + */ ipcMain.handle('save-logs', async (_, data) => { const cliLogFiles = fs .readdirSync(paths.dotOperateDirectory) @@ -794,11 +770,12 @@ ipcMain.handle('save-logs', async (_, data) => { fs.writeFileSync(osInfoFilePath, osInfo); // Persistent store - if (data.store) + if (data.store) { sanitizeLogs({ name: 'store.txt', data: JSON.stringify(data.store, null, 2), }); + } // Other debug data: balances, addresses, etc. if (data.debugData) { @@ -824,6 +801,16 @@ ipcMain.handle('save-logs', async (_, data) => { }); } + // Bridge logs + try { + const bridgeLogFilePath = path.join(paths.bridgeDirectory, 'bridge.json'); + if (fs.existsSync(bridgeLogFilePath)) { + sanitizeLogs({ name: 'bridge.json', filePath: bridgeLogFilePath }); + } + } catch (e) { + logger.electron(e); + } + // Agent logs try { fs.readdirSync(paths.servicesDir).forEach((serviceDirName) => { @@ -898,12 +885,12 @@ ipcMain.handle('save-logs', async (_, data) => { } // Remove temporary files - fs.existsSync(paths.osPearlTempDir) && + if (fs.existsSync(paths.osPearlTempDir)) { fs.rmSync(paths.osPearlTempDir, { recursive: true, force: true, }); - + } return result; }); diff --git a/electron/preload.js b/electron/preload.js index 205aa5cdf..f1766111e 100644 --- a/electron/preload.js +++ b/electron/preload.js @@ -35,8 +35,6 @@ contextBridge.exposeInMainWorld('electronAPI', { saveLogs: (data) => ipcRenderer.invoke('save-logs', data), openPath: (filePath) => ipcRenderer.send('open-path', filePath), getAppVersion: () => ipcRenderer.invoke('app-version'), - validateTwitterLogin: (credentials) => - ipcRenderer.invoke('validate-twitter-login', credentials), healthCheck: () => ipcRenderer.invoke('health-check'), agentActivityWindow, }); diff --git a/electron/public/chains/base-chain.png b/electron/public/chains/base-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..38b747114cb007e83cd4e652f5ab7ab2e0ad6596 GIT binary patch literal 2894 zcmV-U3$gTxP)GE_^QR!ZL3?|D8MC_s8D8H~Vq(1CDnjDDiIJf8NK;?7RR~ z**5YDbZDBt(J+65f_Q;t^Zc(MLWwD#0Jh^5+%luPg?s!C<43a_Cl-hz6RUem zT@SDmpTfKRtkg|NIDry60${wi<=r+s*cfPxsGhTZ-RualI>;t~-S{GpQjdnG(I5U+XQZcv zLU>|);NvT}hb7|E;6CPLegW*noY$|zA&lk64}kqG6cT!clMizd!rbcz^9f)#J~Si$ z436L^KmNTP@ns+vAq3brp5O^ml3oBd>0{h?vPqM!zW$&Xu0Ac7CRsdsWCh`Xrb!Cd z(YGK zLJ!8zLs2VJYwx+3nb|#n-N~aK)lUCdo>-q2hJu3+9LynvrZk*!XVGi|a8U0v#$Wuk zI-`CP4no4rp{#p9>8Y(ub>2te|6#{J{Asj zPjDM|r&R^hJ-`x9p~NB^pQw9+H_7hniA)y2PQ0%*)w}4%@1QCI-f+X@eFD=wK&p~r zR+#X4<9DG59=-=1;>k7~F942yrNr;_z#D%MUK5ohc#0R8?HP976AbUIa zo}ca&gM&$QognDudR72-@<&Vn3T|uR;r)(+)RJTN(GkFs?C2MMvmPjTRNG^rEr6En zRCf<*e4FFaGTyj&xD@+7KqXf~(pN$3C+n*Oa>PCz=SPM-8C|UuCzCq6rqSx1ifv~5S zUS{Z?{Oq4D(s@8=vVc1f!jFD^M6Yp(pR)=O%K^%Gh(p;BzQ(m%5Eg)=(=ZA_9^p>( zZ<-JgxH|EpYS0j`{)t?;`zNu17BK|W;8|2^`VAvIg~kh@gw%ckF}wg494~+p!jsIU z@B&zHI1dm(s1o3M^`dMB$#c?6aIPh~1wptE!0!drMYL%}fM#gEL=ZwUHhD%PJk#3b za`0;i;RT@2YsqWe!Z%C;#d^_Eoov43(W4=IVq+v40!ZTvcoY$BPZKBz;L`{mMMMP< zq7mW-4G2Gb?DnN3~B(82w~0{AFsj8aNg=+YduP%kyf zbxTV0UqqTkOZ!bhH3iCn|UWqV@qR07t&keu`*ZJNfZ< z1}S*~&JAoG`+Q)KbK@QBdLeSGEhl#m-;J*{I*1XTC&-rZ9=p?b{V&jBsPyY)^1Xpd zUV!jJGaM{B42N4PJzC!~(T0-+pqL8~mO6_pf{yV;H+uBKY2RnT<4M0V{qEo!96*td z2o^0T=(v5=gm@W8(|%>T0PJQF)y{tu!Pegvr#g6Yr9AR2C!^~AL1sH2poKFC?-&|{ zBZ3#D>LOsNxBr2<@uRlQrV?OQ*j20r_3fU#@4o&3IMisMoFgi$7y z7XY~*pP7Gg2nTQlQKgA;4saoiYavd&TWl8dE`o=%{(3qAu;E~cmvD5pAdOFNP}UA) z9Q9oPICHl_c4EyxigW@X>@a3UAi8H@5@qxT$;{q|>ao6;CT?SWmc*}@^a3C|@xJ-` z2#zU(5a{j|=kzCWWJdo?iC-`C34l1v2L>sc5ID-2+_AjN>E_rIWBfYiV15CR-S{GD zMw}Dup+hn7WU@R??PBT5J9d(NkM3N3Kb-A*8r;X6WD@|B!X;cub{(7ht-Na=8_GS4 z>Ed5}Zby0nZiQ#Pzn<*qo|9|>AT}xF{6Gx_fh&#dtU(X4TARO<8Ot`F$npBiuEBE~ z>BB@O>Dx-1^bL|-0HlB-7=&Jdhb%Kx@I1qnpY``Q?9}L7lc3RQ=mHsg5E0`O83B+I zh@c{f8K1}rfOrvTBWipidssAA4qM>7T?CITyro;%_(cA+a4UlK!F$j=8Q`_NkvG2m zuQl0;>*lNOhNr5Na&adux&k0OG2c8z;B4)nBCxhUnzp4YEBXQ;J~>QFq!I5&;ih8< z^8zkY#_~6wRt{dHR{B-Fd2!o_Ag4Fyb-vR*FQ` zg-{^FcPN$sIxta;jS!S>Om$8H4d0=d0_eaTAwb8VzEr4Ej z<86~EZ<}{~55=8TY$o&eJc+Y_qkRpV+13Cb^kQM@0o86m6~L-CpG5O-ijv6B3J sd_EB+Uu_E=8v2{$H6P2}Bi5_Lk7(?Q<;;|^Z~y=R07*qoM6N<$g4OwIPXGV_ literal 0 HcmV?d00001 diff --git a/electron/public/chains/ethereum-chain.png b/electron/public/chains/ethereum-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..f9685c478d193338893ec9837b3d39b83c00bca5 GIT binary patch literal 2769 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 AYXATM literal 0 HcmV?d00001 diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 381565533..f37c08092 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -102,15 +102,13 @@ export type ConfigurationTemplate = { monthly_gas_estimate: number; fund_requirements: { // zero address means native currency - [tokenAddress: string]: FundRequirementsTemplate; + [tokenAddress: Address]: { + agent: number; + safe: number; + }; }; }; -export type FundRequirementsTemplate = { - agent: number; - safe: number; -}; - export type DeployedNodes = { agent: string[]; tendermint: string[]; @@ -145,10 +143,12 @@ export type MiddlewareWalletResponse = { safe_nonce: number; }; +export type MasterSafeBalanceRecord = { + master_safe: { [tokenAddress: Address]: number | string }; +}; + export type AddressBalanceRecord = { - [address: Address]: { - [tokenAddress: Address]: number; - }; + [address: Address]: { [tokenAddress: Address]: number | string }; }; export type BalancesAndFundingRequirements = { @@ -161,10 +161,14 @@ export type BalancesAndFundingRequirements = { * If it not present or is 0, the balance is sufficient. */ refill_requirements: Partial<{ - [chain in MiddlewareChain]: AddressBalanceRecord; + [chain in MiddlewareChain]: AddressBalanceRecord | MasterSafeBalanceRecord; }>; + total_requirements: { + [chain in MiddlewareChain]: AddressBalanceRecord | MasterSafeBalanceRecord; + }; bonded_olas: { [chain in MiddlewareChain]: number; }; + is_refill_required: boolean; allow_start_agent: boolean; }; diff --git a/frontend/components/AgentActivity/index.tsx b/frontend/components/AgentActivity/index.tsx index 36473ff54..1ec59511b 100644 --- a/frontend/components/AgentActivity/index.tsx +++ b/frontend/components/AgentActivity/index.tsx @@ -106,7 +106,7 @@ export const AgentActivityPage = () => { Current activity - + {currentActivityRoundName} diff --git a/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/FireworksApiField.tsx b/frontend/components/AgentForms/MemeooorrAgentForm/FireworksApiField.tsx similarity index 98% rename from frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/FireworksApiField.tsx rename to frontend/components/AgentForms/MemeooorrAgentForm/FireworksApiField.tsx index f0a2337aa..0d8acc0c8 100644 --- a/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/FireworksApiField.tsx +++ b/frontend/components/AgentForms/MemeooorrAgentForm/FireworksApiField.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components'; import { InfoTooltip } from '@/components/InfoTooltip'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { commonFieldProps } from '../shared/formUtils'; +import { commonFieldProps } from '../common/formUtils'; const { Text } = Typography; diff --git a/frontend/components/AgentForms/MemeooorrAgentForm/MemeooorrAgentForm.tsx b/frontend/components/AgentForms/MemeooorrAgentForm/MemeooorrAgentForm.tsx new file mode 100644 index 000000000..64d13a5e2 --- /dev/null +++ b/frontend/components/AgentForms/MemeooorrAgentForm/MemeooorrAgentForm.tsx @@ -0,0 +1,224 @@ +import { + Button, + Divider, + Flex, + Form, + FormInstance, + Input, + Typography, +} from 'antd'; +import React, { useCallback, useMemo, useState } from 'react'; +import { useUnmount } from 'usehooks-ts'; + +import { CustomAlert } from '@/components/Alert'; +import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { useSharedContext } from '@/hooks/useSharedContext'; + +import { commonFieldProps, emailValidateMessages } from '../common/formUtils'; +import { InvalidGeminiApiCredentials } from '../common/InvalidGeminiApiCredentials'; +import { FireworksApiFields } from './FireworksApiField'; +import { MemeooorrFormValues } from './types'; +import { useMemeFormValidate } from './useMemeFormValidate'; + +const { Title, Text } = Typography; + +type XAccountApiTokensProps = { showTokensRequiredMessage?: boolean }; + +const XAccountApiTokens = ({ + showTokensRequiredMessage, +}: XAccountApiTokensProps) => ( + + + X account API tokens + + + X account API tokens enable your agent to view X and interact with other + agents. To get the API tokens, please refer to the{' '} + + Step-by-step guide + {' '} + {UNICODE_SYMBOLS.EXTERNAL_LINK}. + + {showTokensRequiredMessage && ( + + X account API tokens are required. + + } + /> + )} + +); + +type MemeooorrAgentFormProps = { + isFormEnabled?: boolean; + initialValues?: MemeooorrFormValues; + agentFormType: 'view' | 'create' | 'update'; + form?: FormInstance; + onSubmit: (values: MemeooorrFormValues) => Promise; +}; + +/** + * Form for setting up a Memeooorr agent (To setup and update the agent). + */ +export const MemeooorrAgentForm = ({ + isFormEnabled = true, + agentFormType, + initialValues, + onSubmit, + form: formInstance, +}: MemeooorrAgentFormProps) => { + const [formState] = Form.useForm(); + + const { isMemeooorrFieldUpdateCompleted } = useSharedContext(); + const form = useMemo( + () => formInstance || formState, + [formInstance, formState], + ); + const [isSubmitting, setIsSubmitting] = useState(false); + + const { + submitButtonText, + setSubmitButtonText, + geminiApiKeyValidationStatus, + setGeminiApiKeyValidationStatus, + validateForm, + } = useMemeFormValidate(); + + const onFinish = useCallback( + async (values: MemeooorrFormValues) => { + try { + setIsSubmitting(true); + + const isValidated = await validateForm(values); + if (!isValidated) return; + await onSubmit(values); + } finally { + setSubmitButtonText('Continue'); + setIsSubmitting(false); + } + }, + [onSubmit, setIsSubmitting, setSubmitButtonText, validateForm], + ); + + // Clean up + useUnmount(async () => { + setIsSubmitting(false); + setGeminiApiKeyValidationStatus('unknown'); + setSubmitButtonText('Continue'); + }); + + const isFormDisabled = !isFormEnabled || isSubmitting; + + return ( + + form={form} + initialValues={initialValues} + onFinish={onFinish} + disabled={isFormDisabled} + validateMessages={emailValidateMessages} + variant={agentFormType === 'view' ? 'borderless' : 'outlined'} + name="setup-your-memeooorr-agent" + layout="vertical" + > + + + + + + + + {geminiApiKeyValidationStatus === 'invalid' && ( + + )} + + + + {/* X account tokens */} + + + + + { + if (e.key === '@') { + e.preventDefault(); + } + }} + /> + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/frontend/components/AgentForms/MemeooorrAgentForm/index.ts b/frontend/components/AgentForms/MemeooorrAgentForm/index.ts new file mode 100644 index 000000000..554b0d336 --- /dev/null +++ b/frontend/components/AgentForms/MemeooorrAgentForm/index.ts @@ -0,0 +1,2 @@ +export { MemeooorrAgentForm } from './MemeooorrAgentForm'; +export type { MemeooorrFormValues, XCredentialsKeys } from './types'; diff --git a/frontend/components/AgentForms/MemeooorrAgentForm/types.ts b/frontend/components/AgentForms/MemeooorrAgentForm/types.ts new file mode 100644 index 000000000..a7c84bd45 --- /dev/null +++ b/frontend/components/AgentForms/MemeooorrAgentForm/types.ts @@ -0,0 +1,20 @@ +export type MemeooorrFormValues = { + personaDescription: string; + geminiApiKey: string; + fireworksApiKey: string; + fireworksApiEnabled: boolean; + fireworksApiKeyName?: string; + xUsername: string; + xConsumerApiKey: string; + xConsumerApiSecret: string; + xBearerToken: string; + xAccessToken: string; + xAccessTokenSecret: string; +}; + +export type XCredentialsKeys = + | 'TWEEPY_CONSUMER_API_KEY' + | 'TWEEPY_CONSUMER_API_KEY_SECRET' + | 'TWEEPY_BEARER_TOKEN' + | 'TWEEPY_ACCESS_TOKEN' + | 'TWEEPY_ACCESS_TOKEN_SECRET'; diff --git a/frontend/components/AgentForms/MemeooorrAgentForm/useMemeFormValidate.ts b/frontend/components/AgentForms/MemeooorrAgentForm/useMemeFormValidate.ts new file mode 100644 index 000000000..9c27fb8f1 --- /dev/null +++ b/frontend/components/AgentForms/MemeooorrAgentForm/useMemeFormValidate.ts @@ -0,0 +1,53 @@ +import { useCallback, useState } from 'react'; + +import { validateGeminiApiKey, ValidationStatus } from '../common/validations'; + +export type MemeooorrFieldValuesToValidate = { + personaDescription: string; + geminiApiKey: string; + fireworksApiKey: string; +}; + +export const useMemeFormValidate = () => { + const [isValidating, setIsValidating] = useState(false); + const [submitButtonText, setSubmitButtonText] = useState('Continue'); + const [geminiApiKeyValidationStatus, setGeminiApiKeyValidationStatus] = + useState('unknown'); + + const handleValidate = useCallback( + async (values: MemeooorrFieldValuesToValidate): Promise => { + setIsValidating(true); + + setGeminiApiKeyValidationStatus('unknown'); + setSubmitButtonText('Validating Gemini API key...'); + + try { + const isGeminiApiValid = await validateGeminiApiKey( + values.geminiApiKey, + ); + setGeminiApiKeyValidationStatus(isGeminiApiValid ? 'valid' : 'invalid'); + if (!isGeminiApiValid) return false; + + // wait for agent setup to complete + setSubmitButtonText('Setting up agent...'); + + return true; + } catch (error) { + console.error('Error validating meme form:', error); + } finally { + setIsValidating(false); + } + return false; + }, + [], + ); + + return { + isValidating, + submitButtonText, + setSubmitButtonText, + geminiApiKeyValidationStatus, + setGeminiApiKeyValidationStatus, + validateForm: handleValidate, + }; +}; diff --git a/frontend/components/SetupPage/SetupYourAgent/shared/InvalidGeminiApiCredentials.tsx b/frontend/components/AgentForms/common/InvalidGeminiApiCredentials.tsx similarity index 100% rename from frontend/components/SetupPage/SetupYourAgent/shared/InvalidGeminiApiCredentials.tsx rename to frontend/components/AgentForms/common/InvalidGeminiApiCredentials.tsx diff --git a/frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts b/frontend/components/AgentForms/common/formUtils.ts similarity index 84% rename from frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts rename to frontend/components/AgentForms/common/formUtils.ts index 8405763ef..19239019c 100644 --- a/frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts +++ b/frontend/components/AgentForms/common/formUtils.ts @@ -2,17 +2,31 @@ import { FormItemProps } from 'antd'; export const requiredRules = [{ required: true, message: 'Field is required' }]; export const validateMessages = { required: 'Field is required' }; + export const commonFieldProps: FormItemProps = { rules: requiredRules, hasFeedback: true, } as const; +/** + * Field properties for optional form fields. These fields are not required. + */ +export const optionalFieldProps: FormItemProps = { + rules: [{ required: false }], +} as const; + export const agentFieldProps: FormItemProps = { ...commonFieldProps, validateFirst: true, normalize: (value: string) => value.trim(), } as const; +export const agentFieldOptionalProps: FormItemProps = { + ...optionalFieldProps, + validateFirst: true, + normalize: (value: string) => value.trim(), +} as const; + export const emailValidateMessages = { required: 'Field is required', types: { email: 'Enter a valid email' }, diff --git a/frontend/components/SetupPage/SetupYourAgent/shared/labels.tsx b/frontend/components/AgentForms/common/labels.tsx similarity index 100% rename from frontend/components/SetupPage/SetupYourAgent/shared/labels.tsx rename to frontend/components/AgentForms/common/labels.tsx diff --git a/frontend/components/AgentForms/common/validations.ts b/frontend/components/AgentForms/common/validations.ts new file mode 100644 index 000000000..870986ce3 --- /dev/null +++ b/frontend/components/AgentForms/common/validations.ts @@ -0,0 +1,20 @@ +export type ValidationStatus = 'valid' | 'invalid' | 'unknown'; + +/** + * Validate the Google Gemini API key + */ +export const validateGeminiApiKey = async (apiKey: string) => { + if (!apiKey) return false; + + try { + // sample request to fetch the models + const apiUrl = + 'https://generativelanguage.googleapis.com/v1/models?key=' + apiKey; + const response = await fetch(apiUrl); + + return response.ok; + } catch (error) { + console.error('Error validating Gemini API key:', error); + return false; + } +}; diff --git a/frontend/components/ExportLogsButton.tsx b/frontend/components/ExportLogsButton.tsx new file mode 100644 index 000000000..dab2eab6e --- /dev/null +++ b/frontend/components/ExportLogsButton.tsx @@ -0,0 +1,63 @@ +import { Button, ButtonProps, message } from 'antd'; +import { useCallback, useEffect, useState } from 'react'; + +import { useElectronApi } from '@/hooks/useElectronApi'; +import { useLogs } from '@/hooks/useLogs'; + +const LogsSavedMessage = ({ onClick }: { onClick: () => void }) => ( + + Logs saved + + +); + +type ExportLogsButtonProps = { size?: ButtonProps['size'] }; + +export const ExportLogsButton = ({ size }: ExportLogsButtonProps) => { + const { openPath, saveLogs } = useElectronApi(); + const logs = useLogs(); + + const [isLoading, setIsLoading] = useState(false); + const [canSaveLogs, setCanSaveLogs] = useState(false); + + const onSaveLogs = useCallback(() => setCanSaveLogs(true), []); + + useEffect(() => { + if (isLoading) return; + if (!logs) return; + if (!canSaveLogs) return; + + setIsLoading(true); + saveLogs?.(logs) + .then((result) => { + if (result.success) { + message.success({ + content: ( + openPath?.(result.dirPath)} /> + ), + duration: 10, + }); + } else { + message.error('Save logs failed or cancelled'); + } + }) + .finally(() => { + setIsLoading(false); + setCanSaveLogs(false); + }); + }, [canSaveLogs, isLoading, logs, openPath, saveLogs]); + + return ( + + ); +}; diff --git a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx index 06cf5d678..8c18a198f 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx @@ -3,7 +3,6 @@ import { ErrorBoundary } from 'next/dist/client/components/error-boundary'; import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; -import { ErrorComponent } from '@/components/errors/ErrorComponent'; import { useServices } from '@/hooks/useServices'; import { useActiveStakingContractDetails } from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; @@ -17,6 +16,11 @@ import { AgentRunningButton } from './AgentRunningButton'; import { AgentStartingButton } from './AgentStartingButton'; import { AgentStoppingButton } from './AgentStoppingButton'; +// TODO: add better error handling +const ErrorComponent = () => { + return Something went wrong; +}; + export const AgentButton = () => { const { isLoading: isServicesLoading, diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index 767562f80..42b57b247 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -16,6 +16,7 @@ import { useNeedsFunds } from '@/hooks/useNeedsFunds'; import { usePageState } from '@/hooks/usePageState'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; +import { useSharedContext } from '@/hooks/useSharedContext'; import { useActiveStakingContractDetails, useStakingContractContext, @@ -33,6 +34,7 @@ import { updateServiceIfNeeded } from '@/utils/service'; */ const useServiceDeployment = () => { const { showNotification } = useElectronApi(); + const { isMemeooorrFieldUpdateCompleted } = useSharedContext(); const { goto: gotoPage } = usePageState(); const { masterWallets, masterSafes, masterEoa } = useMasterWalletContext(); @@ -96,6 +98,10 @@ const useServiceDeployment = () => { // and rely on canStartAgent if (!selectedService && isInitialFunded) return !needsInitialFunding; + // agent specific checks + // If the memeooorr field update is not completed, can't start the agent + if (!isMemeooorrFieldUpdateCompleted) return false; + // allow starting based on refill requirements return canStartAgent; }, [ @@ -112,6 +118,7 @@ const useServiceDeployment = () => { needsInitialFunding, selectedStakingProgramMeta?.deprecated, canStartAgent, + isMemeooorrFieldUpdateCompleted, ]); const pauseAllPolling = useCallback(() => { diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index 993965c53..178a58083 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -1,12 +1,17 @@ import { CopyOutlined } from '@ant-design/icons'; -import { Button, Flex, message, Tooltip, Typography } from 'antd'; +import { Button, Flex, message, Segmented, Tooltip, Typography } from 'antd'; import Link from 'next/link'; import { forwardRef, useCallback, useMemo, useRef, useState } from 'react'; import { CustomAlert } from '@/components/Alert'; +import { SendFundAction } from '@/components/bridge/types'; import { CHAIN_CONFIG } from '@/config/chains'; import { NA, UNICODE_SYMBOLS } from '@/constants/symbols'; import { SWAP_URL_BY_EVM_CHAIN } from '@/constants/urls'; +import { EvmChainName } from '@/enums/Chain'; +import { Pages } from '@/enums/Pages'; +import { useFeatureFlag } from '@/hooks/useFeatureFlag'; +import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { copyToClipboard } from '@/utils/copyToClipboard'; @@ -17,39 +22,10 @@ import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; -export const AddFundsSection = () => { - const fundSectionRef = useRef(null); - const [isAddFundsVisible, setIsAddFundsVisible] = useState(false); - - const addFunds = useCallback(async () => { - setIsAddFundsVisible(true); - - await delayInSeconds(0.1); - fundSectionRef?.current?.scrollIntoView({ behavior: 'smooth' }); - }, []); - const closeAddFunds = useCallback(() => setIsAddFundsVisible(false), []); - - return ( - <> - - - - - {isAddFundsVisible && } - - ); -}; - const AddFundsWarningAlertSection = () => { const { selectedAgentConfig } = useServices(); const { evmHomeChainId: homeChainId } = selectedAgentConfig; + return ( { ); }; +type AddFundsAddressSectionProps = { + fundingAddress?: string; + truncatedFundingAddress?: string; + handleCopy: () => void; +}; + const AddFundsAddressSection = ({ fundingAddress, truncatedFundingAddress, handleCopy, -}: { - fundingAddress?: string; - truncatedFundingAddress?: string; - handleCopy: () => void; -}) => ( +}: AddFundsAddressSectionProps) => ( ((_, ref) => { ); }); OpenAddFundsSection.displayName = 'OpenAddFundsSection'; + +const AddFundsBy = forwardRef((_, ref) => { + const [isBridgeOnboardingEnabled, isBridgeAddFundsEnabled] = useFeatureFlag([ + 'bridge-onboarding', + 'bridge-add-funds', + ]); + const { selectedAgentConfig } = useServices(); + const { goto } = usePageState(); + + const [fundType, setFundType] = useState('transfer'); + + const { evmHomeChainId: homeChainId } = selectedAgentConfig; + const currentFundingRequirements = CHAIN_CONFIG[homeChainId]; + + const bridgeFundsBtn = useMemo( + () => ( + + ), + [goto, isBridgeAddFundsEnabled], + ); + + return ( + <> + {isBridgeOnboardingEnabled && ( + + + options={[ + { + label: `Send on ${currentFundingRequirements.name}`, + value: 'transfer', + }, + { label: 'Bridge from Ethereum', value: 'bridge' }, + ]} + onChange={setFundType} + value={fundType} + block + className="w-full" + /> + + )} + + {fundType === 'bridge' ? ( + + + Bridge funds from Ethereum directly to your Pearl Safe on{' '} + {EvmChainName[homeChainId]} chain. + + {isBridgeAddFundsEnabled ? ( + bridgeFundsBtn + ) : ( + {bridgeFundsBtn} + )} + + ) : ( + + )} + + ); +}); +AddFundsBy.displayName = 'AddFundsBy'; + +export const AddFundsSection = () => { + const fundSectionRef = useRef(null); + const [isAddFundsVisible, setIsAddFundsVisible] = useState(false); + + const addFunds = useCallback(async () => { + setIsAddFundsVisible(true); + + await delayInSeconds(0.1); + fundSectionRef?.current?.scrollIntoView({ behavior: 'smooth' }); + }, []); + const closeAddFunds = useCallback(() => setIsAddFundsVisible(false), []); + + return ( + <> + + + + + {isAddFundsVisible && } + + ); +}; diff --git a/frontend/components/MainPage/sections/AlertSections/UpdateAgentConfiguration.tsx b/frontend/components/MainPage/sections/AlertSections/UpdateAgentConfiguration.tsx new file mode 100644 index 000000000..43a360ca6 --- /dev/null +++ b/frontend/components/MainPage/sections/AlertSections/UpdateAgentConfiguration.tsx @@ -0,0 +1,45 @@ +import { Button, Flex, Typography } from 'antd'; + +import { CustomAlert } from '@/components/Alert'; +import { Pages } from '@/enums/Pages'; +import { usePageState } from '@/hooks/usePageState'; +import { useSharedContext } from '@/hooks/useSharedContext'; + +const { Text } = Typography; + +export const UpdateAgentConfiguration = () => { + const { goto } = usePageState(); + const { isMemeooorrFieldUpdateCompleted } = useSharedContext(); + + if (isMemeooorrFieldUpdateCompleted) return null; + + return ( + + + Action required: Update agent’s configurations + + + + The latest update almost eliminates the possibility of your X + account being suspended. To benefit from these improvements, you + need to update your agent's configurations. + + + + + } + /> + ); +}; diff --git a/frontend/components/MainPage/sections/AlertSections/YourAgentCannotSignIn.tsx b/frontend/components/MainPage/sections/AlertSections/YourAgentCannotSignIn.tsx deleted file mode 100644 index b16e7a931..000000000 --- a/frontend/components/MainPage/sections/AlertSections/YourAgentCannotSignIn.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { Button, Flex, Typography } from 'antd'; -import { isEmpty } from 'lodash'; -import { useMemo } from 'react'; - -import { CustomAlert } from '@/components/Alert'; -import { Pages } from '@/enums/Pages'; -import { useElectronApi } from '@/hooks/useElectronApi'; -import { usePageState } from '@/hooks/usePageState'; -import { useServices } from '@/hooks/useServices'; -import { useSharedContext } from '@/hooks/useSharedContext'; - -const { Text } = Typography; - -const ENV_VARS_WITH_X_ISSUES = [ - 'TWIKIT_USERNAME', - 'TWIKIT_EMAIL', - 'TWIKIT_COOKIES', -]; - -export const useHealthCheck = () => { - const { deploymentDetails } = useServices(); - const { showNotification } = useElectronApi(); - const { isHealthCheckAlertShown, setHealthCheckAlertShown } = - useSharedContext(); - - return useMemo(() => { - if (!deploymentDetails || isEmpty(deploymentDetails)) { - return true; - } - - const { healthcheck } = deploymentDetails; - if (isEmpty(healthcheck) || !healthcheck.env_var_status?.needs_update) { - return true; - } - - const envVarsKeys = Object.keys(healthcheck.env_var_status?.env_vars || {}); - const hasIssues = envVarsKeys.some((key) => - ENV_VARS_WITH_X_ISSUES.includes(key), - ); - if (!hasIssues) return true; - - if (!isHealthCheckAlertShown) { - setHealthCheckAlertShown(true); - showNotification?.( - 'Your agent cannot sign in to X. Please check that your credentials are correct or verify if your X account has been suspended.', - ); - } - return false; - }, [ - deploymentDetails, - showNotification, - isHealthCheckAlertShown, - setHealthCheckAlertShown, - ]); -}; - -export const YourAgentCannotSignIn = () => { - const { goto } = usePageState(); - const hasHealthCheckPassed = useHealthCheck(); - - if (hasHealthCheckPassed) return null; - - return ( - - - Your agent cannot sign in to X - - - - Check your X credentials in Pearl and verify if your X account has - been suspended. If suspended, create a new X account and update your - credentials in Pearl. - - - - - } - /> - ); -}; diff --git a/frontend/components/MainPage/sections/AlertSections/index.tsx b/frontend/components/MainPage/sections/AlertSections/index.tsx index 471e6e90f..307061aa6 100644 --- a/frontend/components/MainPage/sections/AlertSections/index.tsx +++ b/frontend/components/MainPage/sections/AlertSections/index.tsx @@ -6,8 +6,8 @@ import { AvoidSuspensionAlert } from './AvoidSuspensionAlert'; import { ContractDeprecatedAlert } from './ContractDeprecatedAlert'; import { LowFunds } from './LowFunds/LowFunds'; import { NoAvailableSlotsOnTheContract } from './NoAvailableSlotsOnTheContract'; +import { UpdateAgentConfiguration } from './UpdateAgentConfiguration'; import { UpdateAvailableAlert } from './UpdateAvailableAlert'; -import { YourAgentCannotSignIn } from './YourAgentCannotSignIn'; export const AlertSections = () => { const isBackupViaSafeEnabled = useFeatureFlag('backup-via-safe'); @@ -17,7 +17,7 @@ export const AlertSections = () => { {isBackupViaSafeEnabled && } - + diff --git a/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx b/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx index edb62fff7..5c830f6aa 100644 --- a/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx @@ -3,7 +3,7 @@ import Image from 'next/image'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { NA } from '@/constants/symbols'; -import { OPERATE_URL } from '@/constants/urls'; +import { PEARL_URL } from '@/constants/urls'; import { useMainOlasBalance } from '@/context/SharedProvider/useMainOlasBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useRewardContext } from '@/hooks/useRewardContext'; @@ -70,7 +70,7 @@ export const NotifyRewardsModal = () => { const onTwitterShare = useCallback(() => { const encodedText = encodeURIComponent(SHARE_TEXT); - const encodedURL = encodeURIComponent(`${OPERATE_URL}?pearl=first-reward`); + const encodedURL = encodeURIComponent(`${PEARL_URL}?pearl=first-reward`); window.open( `https://twitter.com/intent/tweet?text=${encodedText}&url=${encodedURL}`, diff --git a/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx b/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx index 5fa058378..d505137ba 100644 --- a/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx @@ -7,7 +7,7 @@ import { FireNoStreak } from '@/components/custom-icons/FireNoStreak'; import { FireStreak } from '@/components/custom-icons/FireStreak'; import { COLOR } from '@/constants/colors'; import { NA } from '@/constants/symbols'; -import { OPERATE_URL } from '@/constants/urls'; +import { PEARL_URL } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { usePageState } from '@/hooks/usePageState'; @@ -41,7 +41,7 @@ const Streak = () => { const encodedText = encodeURIComponent( `🎉 I've just completed a ${optimisticStreak}-day streak with my agent on Pearl and earned OLAS every single day! 🏆 How long can you keep your streak going? \n\nDownload the Pearl app:`, ); - const encodedURL = encodeURIComponent(`${OPERATE_URL}?pearl=share-streak`); + const encodedURL = encodeURIComponent(`${PEARL_URL}?pearl=share-streak`); window.open( `https://twitter.com/intent/tweet?text=${encodedText}&url=${encodedURL}`, diff --git a/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx b/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx deleted file mode 100644 index fa849568d..000000000 --- a/frontend/components/ManageStakingPage/WhatAreStakingContracts.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { Collapse, Flex, Typography } from 'antd'; - -import { CardSection } from '../styled/CardSection'; - -const { Text } = Typography; - -const collapseItems = [ - { - key: 1, - label: What are staking contracts?, - children: ( - - - When your agent goes to work, it participates in staking contracts. - - - Staking contracts define what the agent needs to do, how much OLAS - needs to be staked, etc., to be eligible for rewards. - - - Your agent can only participate in one staking contract at a time. - - - ), - }, -]; - -export const WhatAreStakingContractsSection = () => { - return ( - - - - ); -}; diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index ce4e70df1..fd7a173b4 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,4 +1,4 @@ -import { Card } from 'antd'; +import { Card, Collapse, Flex, Typography } from 'antd'; import { useMemo } from 'react'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; @@ -10,7 +10,42 @@ import { CardTitle } from '../Card/CardTitle'; import { GoToMainPageButton } from '../Pages/GoToMainPageButton'; import { CardSection } from '../styled/CardSection'; import { StakingContractSection } from './StakingContractSection'; -import { WhatAreStakingContractsSection } from './WhatAreStakingContracts'; + +const { Text } = Typography; + +const collapseItems = [ + { + key: 1, + label: What are staking contracts?, + children: ( + + + When your agent goes to work, it participates in staking contracts. + + + Staking contracts define what the agent needs to do, how much OLAS + needs to be staked, etc., to be eligible for rewards. + + + Your agent can only participate in one staking contract at a time. + + + ), + }, +]; + +const WhatAreStakingContractsSection = () => { + return ( + + + + ); +}; export const ManageStakingPage = () => { const { selectedAgentConfig } = useServices(); @@ -98,9 +133,7 @@ export const ManageStakingPage = () => { )} ) => { + const isCopy = (e.ctrlKey || e.metaKey) && e.key === 'c'; + const isPaste = (e.ctrlKey || e.metaKey) && e.key === 'v'; + const isCut = (e.ctrlKey || e.metaKey) && e.key === 'x'; + const isSelectAll = (e.ctrlKey || e.metaKey) && e.key === 'a'; + + if ( + !/[0-9]/.test(e.key) && + e.key !== 'Backspace' && + e.key !== 'Delete' && + e.key !== 'ArrowLeft' && + e.key !== 'ArrowRight' && + e.key !== 'Tab' && + e.key !== '.' && + !isCopy && + !isPaste && + !isCut && + !isSelectAll + ) { + e.preventDefault(); + } + + // Prevent more than one decimal point + const value = e.currentTarget.value; + if (e.key === '.' && value.includes('.')) { + e.preventDefault(); + } +}; + +export const NumberInput = ({ value, ...rest }: InputNumberProps) => ( + + {...rest} + value={typeof value === 'string' ? parseFloat(value) : value} + formatter={(value) => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} + onKeyDown={allowOnlyNumbers} + /> +); diff --git a/frontend/components/Pages/HelpAndSupportPage.tsx b/frontend/components/Pages/HelpAndSupportPage.tsx new file mode 100644 index 000000000..d3fca067f --- /dev/null +++ b/frontend/components/Pages/HelpAndSupportPage.tsx @@ -0,0 +1,74 @@ +import { QuestionCircleOutlined } from '@ant-design/icons'; +import { Card, Flex, Typography } from 'antd'; + +import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { + FAQ_URL, + SUPPORT_URL, + TERMS_AND_CONDITIONS_URL, +} from '@/constants/urls'; + +import { CardTitle } from '../Card/CardTitle'; +import { ExportLogsButton } from '../ExportLogsButton'; +import { CardSection } from '../styled/CardSection'; +import { GoToMainPageButton } from './GoToMainPageButton'; + +const { Title, Paragraph } = Typography; + +const SettingsTitle = () => ( + + + Help & support + + } + /> +); + +export const HelpAndSupport = () => { + return ( + } + bordered={false} + styles={{ + body: { + paddingTop: 0, + paddingBottom: 0, + }, + }} + extra={} + > + + + Frequently asked questions + + + Read FAQ {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + Terms and Conditions {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + + + + Ask for help + + + Get your questions answered by the community. + + + Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + + + + Export logs for troubleshooting + + + + + ); +}; diff --git a/frontend/components/Pages/HelpAndSupportPage/index.tsx b/frontend/components/Pages/HelpAndSupportPage/index.tsx deleted file mode 100644 index 868619187..000000000 --- a/frontend/components/Pages/HelpAndSupportPage/index.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { QuestionCircleOutlined } from '@ant-design/icons'; -import { Button, Card, Flex, message, Typography } from 'antd'; -import { useCallback, useEffect, useState } from 'react'; - -import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { - FAQ_URL, - SUPPORT_URL, - TERMS_AND_CONDITIONS_URL, -} from '@/constants/urls'; -import { useElectronApi } from '@/hooks/useElectronApi'; -import { useLogs } from '@/hooks/useLogs'; - -import { CardTitle } from '../../Card/CardTitle'; -import { CardSection } from '../../styled/CardSection'; -import { GoToMainPageButton } from '../GoToMainPageButton'; - -const { Title, Paragraph } = Typography; - -const SettingsTitle = () => ( - - - Help & support - - } - /> -); - -const LogsSavedMessage = ({ onClick }: { onClick: () => void }) => { - return ( - - Logs saved - - - ); -}; - -export const HelpAndSupport = () => { - const { openPath, saveLogs } = useElectronApi(); - - const logs = useLogs(); - - const [isLoading, setIsLoading] = useState(false); - const [canSaveLogs, setCanSaveLogs] = useState(false); - - const onSaveLogs = useCallback(() => setCanSaveLogs(true), []); - - useEffect(() => { - if (canSaveLogs && logs && !isLoading) { - setIsLoading(true); - saveLogs?.(logs) - .then((result) => { - if (result.success) { - message.success({ - content: ( - openPath?.(result.dirPath)} /> - ), - duration: 10, - }); - } else { - message.error('Save logs failed or cancelled'); - } - }) - .finally(() => { - setIsLoading(false); - setCanSaveLogs(false); - }); - } - }, [canSaveLogs, isLoading, logs, openPath, saveLogs]); - - return ( - } - bordered={false} - styles={{ - body: { - paddingTop: 0, - paddingBottom: 0, - }, - }} - extra={} - > - - - Frequently asked questions - - - Read FAQ {UNICODE_SYMBOLS.EXTERNAL_LINK} - - - Terms and Conditions {UNICODE_SYMBOLS.EXTERNAL_LINK} - - - - - - Ask for help - - - Get your questions answered by the community. - - - Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} - - - - - - Export logs for troubleshooting - - - - - ); -}; diff --git a/frontend/components/SetupPage/AgentIntroduction/constants.ts b/frontend/components/SetupPage/AgentIntroduction/constants.ts index fdcd7ea42..67fe77fb4 100644 --- a/frontend/components/SetupPage/AgentIntroduction/constants.ts +++ b/frontend/components/SetupPage/AgentIntroduction/constants.ts @@ -41,7 +41,7 @@ export const AGENTS_FUND_ONBOARDING_STEPS: OnboardingStep[] = [ export const MODIUS_ONBOARDING_STEPS: OnboardingStep[] = [ { title: 'Your AI portfolio manager', - desc: 'Modius collects real-time market data from CoinGecko and autonomously manages your investments using Balancer and Sturdy — delivering hands-free portfolio growth. Requires ETH and USDC on Mode as initial investments.', + desc: 'Modius collects real-time market data from CoinGecko and autonomously manages your investments using Balancer, Sturdy and Velodrome — delivering hands-free portfolio growth. Requires ETH and USDC on Mode as initial investments.', imgSrc: 'setup-agent-modius-1', }, { @@ -49,11 +49,12 @@ export const MODIUS_ONBOARDING_STEPS: OnboardingStep[] = [ desc: 'Modius learns autonomously, adapts to changing market conditions, and selects the best next strategy to invest on your behalf.', imgSrc: 'setup-agent-modius-2', }, - { - title: 'Take action', - desc: 'Based on its analysis and real-time market data, your Modius agent decides when its more convenient to buy, sell, or hold specific assets.', - imgSrc: 'setup-agent-modius-3', - }, + // TODO: will be added back again. + // { + // title: 'Take action', + // desc: 'Based on its analysis and real-time market data, your Modius agent decides when its more convenient to buy, sell, or hold specific assets.', + // imgSrc: 'setup-agent-modius-3', + // }, ] as const; export const OPTIMUS_ONBOARDING_STEPS: OnboardingStep[] = [ diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx new file mode 100644 index 000000000..2218f745f --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx @@ -0,0 +1,261 @@ +import { Typography } from 'antd'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +import { CustomAlert } from '@/components/Alert'; +import { BridgeTransferFlow } from '@/components/bridge/BridgeTransferFlow'; +import { BridgingSteps, StepEvent } from '@/components/bridge/BridgingSteps'; +import { CardFlex } from '@/components/styled/CardFlex'; +import { Pages } from '@/enums/Pages'; +import { usePageState } from '@/hooks/usePageState'; +import { BridgingStepStatus, CrossChainTransferDetails } from '@/types/Bridge'; +import { Nullable } from '@/types/Util'; + +import { SetupCreateHeader } from '../../SetupCreateHeader'; +import { BridgeRetryOutcome } from '../types'; +import { useBridgingSteps } from './useBridgingSteps'; +import { useMasterSafeCreationAndTransfer } from './useMasterSafeCreationAndTransfer'; +import { useRetryBridge } from './useRetryBridge'; + +const { Text, Title } = Typography; + +const KeepAppOpenAlert = () => ( + + Keep the app open until bridging is complete. + + } + /> +); + +const Header = () => ( + <> + + + + Bridging in progress + + + + +); + +type BridgeInProgressProps = { + quoteId: string; + bridgeRetryOutcome: Nullable; + onBridgeRetryOutcome: (outcome: Nullable) => void; +} & CrossChainTransferDetails; + +/** + * Bridge in progress screen. + */ +export const BridgeInProgress = ({ + quoteId, + fromChain, + toChain, + transfers, + bridgeRetryOutcome, + onBridgeRetryOutcome, +}: BridgeInProgressProps) => { + const { goto } = usePageState(); + const symbols = transfers.map((transfer) => transfer.toSymbol); + + const [isBridgeRetrying, setIsBridgeRetrying] = useState(false); + const refetchBridgeExecute = useRetryBridge(); + + const { isBridging, isBridgingFailed, isBridgingCompleted, bridgeStatus } = + useBridgingSteps(quoteId, symbols); + const { + isPending: isLoadingMasterSafeCreation, + isError: isErrorMasterSafeCreation, + data: masterSafeDetails, + mutateAsync: createMasterSafe, + } = useMasterSafeCreationAndTransfer(symbols); + + const isSafeCreated = masterSafeDetails?.isSafeCreated; + const isTransferCompleted = + masterSafeDetails?.masterSafeTransferStatus === 'FINISHED'; + + // Create master safe after the bridging is completed + // and if the master safe is not created yet. + useEffect(() => { + // if refill is required, do not create master safe. + if (bridgeRetryOutcome === 'NEED_REFILL') return; + + // if bridging is in progress or if it has failed, do not create master safe. + if (isBridging) return; + if (isBridgingFailed) return; + if (!isBridgingCompleted) return; + + // if master safe creation is in progress or if it has failed, do not create master safe. + if (isLoadingMasterSafeCreation) return; + if (isErrorMasterSafeCreation) return; + if (masterSafeDetails?.isSafeCreated) return; + + createMasterSafe(); + }, [ + bridgeRetryOutcome, + isBridgingCompleted, + isBridging, + isBridgingFailed, + isLoadingMasterSafeCreation, + masterSafeDetails, + isErrorMasterSafeCreation, + createMasterSafe, + ]); + + // Redirect to main page if all 3 steps are completed + useEffect(() => { + // if retry outcome is not null, do not redirect. + if (bridgeRetryOutcome === 'NEED_REFILL') return; + + // if bridging is in progress or if it has failed, do not redirect. + if (isBridging) return; + if (isBridgingFailed) return; + if (!isBridgingCompleted) return; + + // if master safe creation is in progress or if it has failed, do not redirect. + if (isLoadingMasterSafeCreation) return; + if (!isSafeCreated) return; + if (!isTransferCompleted) return; + + // wait for 3 seconds before redirecting to main page. + const timeoutId = setTimeout(() => goto(Pages.Main), 3000); + return () => clearTimeout(timeoutId); + }, [ + bridgeRetryOutcome, + isBridging, + isBridgingFailed, + isBridgingCompleted, + isLoadingMasterSafeCreation, + isSafeCreated, + isTransferCompleted, + goto, + ]); + + const onBridgeFailRetry = useCallback(() => { + setIsBridgeRetrying(true); + refetchBridgeExecute((e: Nullable) => + onBridgeRetryOutcome(e), + ).finally(() => { + setIsBridgeRetrying(false); + }); + }, [refetchBridgeExecute, onBridgeRetryOutcome]); + + const bridgeDetails = useMemo(() => { + const currentBridgeStatus: BridgingStepStatus = (() => { + if (bridgeRetryOutcome === 'NEED_REFILL') return 'wait'; + if (isBridgingFailed) return 'error'; + if (isBridging) return 'process'; + if (!bridgeStatus) return 'wait'; + if (isBridgingCompleted) return 'finish'; + + return 'process'; + })(); + + return { + status: currentBridgeStatus, + subSteps: (bridgeStatus || []).map((step) => ({ + ...step, + onRetry: onBridgeFailRetry, + onRetryProps: { + isLoading: currentBridgeStatus === 'process' || isBridgeRetrying, + }, + })) satisfies StepEvent[], + }; + }, [ + bridgeRetryOutcome, + isBridging, + isBridgingFailed, + isBridgingCompleted, + bridgeStatus, + isBridgeRetrying, + onBridgeFailRetry, + ]); + + const masterSafeCreationDetails = useMemo(() => { + const currentMasterSafeCreationStatus: BridgingStepStatus = (() => { + if (bridgeRetryOutcome === 'NEED_REFILL') return 'wait'; + if (isBridging || !isBridgingCompleted) return 'wait'; + if (isErrorMasterSafeCreation) return 'error'; + if (isLoadingMasterSafeCreation) return 'process'; + if (isSafeCreated) return 'finish'; + return 'process'; + })(); + + return { + status: currentMasterSafeCreationStatus, + subSteps: [ + { + txnLink: null, // BE to be updated to return the txn link + onRetry: createMasterSafe, + onRetryProps: { + isLoading: currentMasterSafeCreationStatus === 'process', + }, + }, + ] satisfies StepEvent[], + }; + }, [ + bridgeRetryOutcome, + isBridging, + isBridgingCompleted, + isSafeCreated, + isLoadingMasterSafeCreation, + isErrorMasterSafeCreation, + createMasterSafe, + ]); + + const masterSafeTransferDetails = useMemo(() => { + const currentMasterSafeStatus: BridgingStepStatus = (() => { + if (bridgeRetryOutcome === 'NEED_REFILL') return 'wait'; + if (isErrorMasterSafeCreation) return 'error'; + if (isBridging || !isBridgingCompleted || !isSafeCreated) return 'wait'; + return isTransferCompleted ? 'finish' : 'wait'; + })(); + + return { + status: currentMasterSafeStatus, + subSteps: (masterSafeDetails?.transfers || []).map((transfer) => ({ + ...transfer, + onRetry: createMasterSafe, + onRetryProps: { + isLoading: masterSafeCreationDetails.status === 'process', + }, + })) satisfies StepEvent[], + }; + }, [ + bridgeRetryOutcome, + isErrorMasterSafeCreation, + isSafeCreated, + isBridging, + isBridgingCompleted, + isTransferCompleted, + masterSafeCreationDetails, + masterSafeDetails?.transfers, + createMasterSafe, + ]); + + return ( + <> +
      + + + {!!bridgeDetails && ( + + )} + + + ); +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useBridgingSteps.ts b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useBridgingSteps.ts new file mode 100644 index 000000000..ae32a5e7c --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useBridgingSteps.ts @@ -0,0 +1,180 @@ +import { useQuery } from '@tanstack/react-query'; +import { useMemo } from 'react'; + +import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { TokenSymbol } from '@/enums/Token'; +import { useOnlineStatusContext } from '@/hooks/useOnlineStatus'; +import { BridgeService } from '@/service/Bridge'; +import { BridgeStatusResponse, BridgingStepStatus } from '@/types/Bridge'; + +const isBridgingFailedFn = ( + requests: BridgeStatusResponse['bridge_request_status'] = [], +) => + requests + ? requests.some((step) => step.status === 'EXECUTION_FAILED') + : false; + +const isBridgingCompletedFn = ( + requests: BridgeStatusResponse['bridge_request_status'] = [], +) => requests.every((step) => step.status === 'EXECUTION_DONE'); + +const getBridgeStats = ({ + stats, + tokenSymbols, +}: { + hasAnyBridgeFailed?: boolean; + tokenSymbols: TokenSymbol[]; + stats: BridgeStatusResponse['bridge_request_status']; +}) => + stats.map((step, index) => { + const stepStatus: BridgingStepStatus = (() => { + if (step.status === 'EXECUTION_DONE') return 'finish'; + if (step.status === 'EXECUTION_FAILED') return 'error'; + if (step.status === 'EXECUTION_PENDING') return 'process'; + return 'process'; + })(); + + return { + symbol: tokenSymbols[index], + status: stepStatus, + txnLink: step.explorer_link, + }; + }); + +// hook to fetch bridging steps (step 1) +export const useBridgingSteps = ( + quoteId: string, + tokenSymbols: TokenSymbol[], +) => { + const { isOnline } = useOnlineStatusContext(); + + // `/execute` bridge API should be called first before fetching the status. + const { + isLoading: isBridgeExecuteLoading, + isFetching: isBridgeExecuteFetching, + isError: isBridgeExecuteError, + data: bridgeExecuteData, + } = useQuery({ + queryKey: REACT_QUERY_KEYS.BRIDGE_EXECUTE_KEY(quoteId), + queryFn: async () => { + try { + return await BridgeService.executeBridge(quoteId); + } catch (error) { + console.error('Error executing bridge', error); + throw error; + } + }, + enabled: !!quoteId && isOnline, + retry: false, + refetchOnWindowFocus: false, + refetchInterval: false, + }); + + const isBridgingExecuteFailed = isBridgingFailedFn( + bridgeExecuteData?.bridge_request_status, + ); + const isBridgingExecuteCompleted = isBridgingCompletedFn( + bridgeExecuteData?.bridge_request_status, + ); + + const { + isLoading: isBridgeStatusLoading, + isError: isBridgeStatusError, + data: bridgeStatusData, + } = useQuery({ + queryKey: REACT_QUERY_KEYS.BRIDGE_STATUS_BY_QUOTE_ID_KEY(quoteId), + queryFn: async ({ signal }) => { + try { + return await BridgeService.getBridgeStatus(quoteId, signal); + } catch (error) { + console.error('Error fetching bridge status', error); + throw error; + } + }, + // fetch by interval until the status is FINISHED + refetchInterval: + isBridgingExecuteFailed || isBridgingExecuteCompleted + ? false + : FIVE_SECONDS_INTERVAL, + enabled: !!quoteId && isOnline && !!bridgeExecuteData, + retry: false, + refetchOnWindowFocus: false, + }); + + const isBridging = useMemo(() => { + if (isBridgeExecuteLoading) return true; + if (isBridgeStatusLoading) return true; + return false; + }, [isBridgeExecuteLoading, isBridgeStatusLoading]); + + const isBridgingCompleted = useMemo(() => { + // If the bridge execute itself has EXECUTION_DONE, we can consider the bridging as completed. + // and we don't need to check the status. + if (isBridgingExecuteCompleted) return true; + + return isBridgingCompletedFn(bridgeStatusData?.bridge_request_status); + }, [isBridgingExecuteCompleted, bridgeStatusData]); + + const hasAnyBridgeFailed = useMemo( + () => + isBridgingExecuteFailed || + isBridgingFailedFn(bridgeStatusData?.bridge_request_status), + [isBridgingExecuteFailed, bridgeStatusData], + ); + + // if the bridge status is 'EXECUTION_FAILED' or 'EXECUTION_PENDING' + // and the API has error, we can consider the bridging as failed. + const isBridgingFailed = useMemo(() => { + if (isBridgeExecuteError) return true; + if (isBridgeStatusError) return true; + if (hasAnyBridgeFailed) return true; + return false; + }, [isBridgeExecuteError, isBridgeStatusError, hasAnyBridgeFailed]); + + const executeBridgeSteps = useMemo(() => { + if (isBridgeExecuteLoading) return; + if (isBridgeExecuteFetching) return; + if (isBridgeExecuteError) return; + if (!bridgeExecuteData) return; + + return getBridgeStats({ + stats: bridgeExecuteData.bridge_request_status, + tokenSymbols, + }); + }, [ + isBridgeExecuteLoading, + isBridgeExecuteFetching, + isBridgeExecuteError, + bridgeExecuteData, + tokenSymbols, + ]); + + const statusBridgeSteps = useMemo(() => { + if (isBridgeStatusLoading) return; + if (isBridgeStatusError) return; + if (!bridgeStatusData) return; + + return getBridgeStats({ + stats: bridgeStatusData.bridge_request_status, + tokenSymbols, + }); + }, [ + isBridgeStatusLoading, + isBridgeStatusError, + bridgeStatusData, + tokenSymbols, + ]); + + const bridgeStatus = useMemo(() => { + if (isBridgingExecuteCompleted) return executeBridgeSteps; + return statusBridgeSteps; + }, [isBridgingExecuteCompleted, executeBridgeSteps, statusBridgeSteps]); + + return { + isBridging, + isBridgingFailed, + isBridgingCompleted, + bridgeStatus, + }; +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useMasterSafeCreationAndTransfer.ts b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useMasterSafeCreationAndTransfer.ts new file mode 100644 index 000000000..7f96651d6 --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useMasterSafeCreationAndTransfer.ts @@ -0,0 +1,55 @@ +import { useMutation } from '@tanstack/react-query'; + +import { TokenSymbol } from '@/enums/Token'; +import { useBackupSigner } from '@/hooks/useBackupSigner'; +import { useElectronApi } from '@/hooks/useElectronApi'; +import { useServices } from '@/hooks/useServices'; +import { WalletService } from '@/service/Wallet'; +import { BridgingStepStatus } from '@/types/Bridge'; + +/** + * Hook to create master safe and transfer funds (step 2 and 3) + */ +export const useMasterSafeCreationAndTransfer = ( + tokenSymbols: TokenSymbol[], +) => { + const electronApi = useElectronApi(); + const backupSignerAddress = useBackupSigner(); + const { selectedAgentType, selectedAgentConfig } = useServices(); + + const chain = selectedAgentConfig.middlewareHomeChainId; + + return useMutation({ + mutationFn: async () => { + try { + const response = await WalletService.createSafe( + chain, + backupSignerAddress, + ); + + return { + isSafeCreated: true, + txnLink: response.create_tx, + + // NOTE: Currently, both creation and transfer are handled in the same API call. + // Hence, the response contains the transfer status as well. + masterSafeTransferStatus: 'FINISHED', + transfers: tokenSymbols.map((symbol) => ({ + symbol, + status: 'finish' as BridgingStepStatus, + txnLink: null, // TODO: to integrate + })), + }; + } catch (error) { + console.error('Safe creation failed:', error); + throw error; + } + }, + onSuccess: () => { + // Since the master safe is created and the transfer is completed, + // we can update the store to indicate that the agent is initially funded. + // TODO: logic to be moved to BE in the future. + electronApi.store?.set?.(`${selectedAgentType}.isInitialFunded`, true); + }, + }); +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useRetryBridge.ts b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useRetryBridge.ts new file mode 100644 index 000000000..61a2d8e8d --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/useRetryBridge.ts @@ -0,0 +1,35 @@ +import { message } from 'antd'; +import { useCallback } from 'react'; + +import { useBalanceAndRefillRequirementsContext } from '@/hooks/useBalanceAndRefillRequirementsContext'; +import { Nullable } from '@/types/Util'; + +import { BridgeRetryOutcome } from '../types'; + +/*** + * Hook to handle retrying the bridge step + * If refill is required, it will navigate to the refill page + */ +export const useRetryBridge = () => { + const { refetch } = useBalanceAndRefillRequirementsContext(); + + return useCallback( + async (onRetryOutcome: (e: Nullable) => void) => { + if (!refetch) return; + + const { data } = await refetch(); + if (!data) return; + + if (data?.is_refill_required) { + onRetryOutcome('NEED_REFILL'); + } else { + message.open({ + icon: null, + content: + "Bridging complete! Please restart the app if you're not redirected automatically.", + }); + } + }, + [refetch], + ); +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx new file mode 100644 index 000000000..4f5d9e629 --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx @@ -0,0 +1,67 @@ +import { Flex, Typography } from 'antd'; + +import { CustomAlert } from '@/components/Alert'; +import { DepositForBridging } from '@/components/bridge/DepositForBridging'; +import { CardFlex } from '@/components/styled/CardFlex'; +import { CardSection } from '@/components/styled/CardSection'; +import { SetupScreen } from '@/enums/SetupScreen'; +import { CrossChainTransferDetails } from '@/types/Bridge'; + +import { SetupCreateHeader } from '../SetupCreateHeader'; + +const { Text, Title } = Typography; + +const FROM_CHAIN_NAME = 'Ethereum'; + +type BridgeOnEvmProps = { + onNext: () => void; + updateQuoteId: (quoteId: string) => void; + updateCrossChainTransferDetails: (details: CrossChainTransferDetails) => void; +}; + +export const BridgeOnEvm = ({ + onNext, + updateQuoteId, + updateCrossChainTransferDetails, +}: BridgeOnEvmProps) => { + return ( + + + + + + + Bridge from {FROM_CHAIN_NAME} + + + The bridged amount covers all funds required to create your account + and run your agent, including fees. No further funds will be needed. + + + + + + Only send funds on Ethereum! + + Full amount of funds is required to initiate the bridging. + + + } + /> + + + + + + ); +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/SetupBridgeOnboarding.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/SetupBridgeOnboarding.tsx new file mode 100644 index 000000000..467e04bf8 --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/SetupBridgeOnboarding.tsx @@ -0,0 +1,94 @@ +import { useCallback, useEffect, useState } from 'react'; + +import { Pages } from '@/enums/Pages'; +import { usePageState } from '@/hooks/usePageState'; +import { CrossChainTransferDetails } from '@/types/Bridge'; +import { Nullable } from '@/types/Util'; + +import { BridgeInProgress } from './BridgeInProgress/BridgeInProgress'; +import { BridgeOnEvm } from './BridgeOnEvm'; +import { BridgeRetryOutcome } from './types'; + +const QUOTE_ID_ERROR = 'Quote ID is required for in progress state'; +const TRANSFER_AMOUNTS_ERROR = + 'Transfer and receiving amounts are required for in progress state'; + +type BridgeState = 'depositing' | 'in_progress'; + +export const SetupBridgeOnboarding = () => { + const { goto } = usePageState(); + const [bridgeState, setBridgeState] = useState('depositing'); + const [quoteId, setQuoteId] = useState>(null); + const [transferAndReceivingAmounts, setTransferAndReceivingAmounts] = + useState>(null); + const [bridgeRetryOutcome, setBridgeRetryOutcome] = + useState>(null); + + const updateQuoteId = useCallback( + (quoteId: string) => setQuoteId(quoteId), + [setQuoteId], + ); + + const updateCrossChainTransferDetails = useCallback( + (details: CrossChainTransferDetails) => + setTransferAndReceivingAmounts(details), + [setTransferAndReceivingAmounts], + ); + + // If retry outcome is set, we need to update the bridge state + useEffect(() => { + if (!bridgeRetryOutcome) return; + + switch (bridgeRetryOutcome) { + case 'NEED_REFILL': { + setBridgeState('depositing'); + setQuoteId(null); + setTransferAndReceivingAmounts(null); + setBridgeRetryOutcome(null); + break; + } + default: + break; + } + }, [bridgeRetryOutcome]); + + const handleNextStep = useCallback(() => { + switch (bridgeState) { + case 'depositing': + setBridgeState('in_progress'); + break; + case 'in_progress': + goto(Pages.Main); + break; + default: + throw new Error('Invalid bridge state'); + } + }, [bridgeState, goto]); + + switch (bridgeState) { + case 'depositing': + return ( + + ); + case 'in_progress': { + if (!quoteId) throw new Error(QUOTE_ID_ERROR); + if (!transferAndReceivingAmounts) throw new Error(TRANSFER_AMOUNTS_ERROR); + return ( + ) => + setBridgeRetryOutcome(e) + } + /> + ); + } + default: + throw new Error('Invalid bridge state!'); + } +}; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/types.ts b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/types.ts new file mode 100644 index 000000000..605282d2b --- /dev/null +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/types.ts @@ -0,0 +1 @@ +export type BridgeRetryOutcome = 'NEED_REFILL'; diff --git a/frontend/components/SetupPage/Create/SetupCreateHeader.tsx b/frontend/components/SetupPage/Create/SetupCreateHeader.tsx index e41af3bf1..97c171cfa 100644 --- a/frontend/components/SetupPage/Create/SetupCreateHeader.tsx +++ b/frontend/components/SetupPage/Create/SetupCreateHeader.tsx @@ -23,12 +23,13 @@ export const SetupCreateHeader = ({ prev }: SetupCreateHeaderProps) => { return ( - + + )} + ); }; diff --git a/frontend/components/SetupPage/Create/SetupPassword.tsx b/frontend/components/SetupPage/Create/SetupPassword.tsx index 44c90af03..c906ef081 100644 --- a/frontend/components/SetupPage/Create/SetupPassword.tsx +++ b/frontend/components/SetupPage/Create/SetupPassword.tsx @@ -2,6 +2,7 @@ import { Button, Checkbox, Form, Input, message, Typography } from 'antd'; import { useState } from 'react'; import { SetupScreen } from '@/enums/SetupScreen'; +import { usePageState } from '@/hooks/usePageState'; import { useSetup } from '@/hooks/useSetup'; import { AccountService } from '@/service/Account'; import { WalletService } from '@/service/Wallet'; @@ -13,6 +14,7 @@ const { Title, Text } = Typography; export const SetupPassword = () => { const { goto, setMnemonic } = useSetup(); + const { setUserLoggedIn } = usePageState(); const [form] = Form.useForm<{ password: string; terms: boolean }>(); const [isLoading, setIsLoading] = useState(false); @@ -28,6 +30,7 @@ export const SetupPassword = () => { .then(({ mnemonic }: { mnemonic: string[] }) => { setMnemonic(mnemonic); goto(SetupScreen.SetupSeedPhrase); + setUserLoggedIn(); }) .catch((e) => { console.error(e); @@ -37,7 +40,7 @@ export const SetupPassword = () => { }; return ( - + Create password Come up with a strong password. diff --git a/frontend/components/SetupPage/SetupRestore.tsx b/frontend/components/SetupPage/SetupRestore.tsx index 996fab59e..18be04f15 100644 --- a/frontend/components/SetupPage/SetupRestore.tsx +++ b/frontend/components/SetupPage/SetupRestore.tsx @@ -32,7 +32,7 @@ export const SetupRestoreMain = () => { } > - + You can recover the Pearl account access by providing the seed phrase you received when setting up your account. @@ -53,8 +53,9 @@ export const SetupRestoreMain = () => { If you don’t have the seed phrase but added a backup wallet to your @@ -190,6 +191,7 @@ export const SetupRestoreViaBackup = () => { } + $noBorder > diff --git a/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/MemeooorrAgentForm.tsx b/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/MemeooorrAgentForm.tsx deleted file mode 100644 index a55bf026a..000000000 --- a/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/MemeooorrAgentForm.tsx +++ /dev/null @@ -1,273 +0,0 @@ -import { Button, Divider, Flex, Form, Input, message, Typography } from 'antd'; -import React, { useCallback, useState } from 'react'; -import { useUnmount } from 'usehooks-ts'; - -import { ServiceTemplate } from '@/client'; -import { CustomAlert } from '@/components/Alert'; -import { SetupScreen } from '@/enums/SetupScreen'; -import { useSetup } from '@/hooks/useSetup'; -import { useStakingProgram } from '@/hooks/useStakingProgram'; - -import { - commonFieldProps, - emailValidateMessages, - requiredRules, -} from '../shared/formUtils'; -import { InvalidGeminiApiCredentials } from '../shared/InvalidGeminiApiCredentials'; -import { onDummyServiceCreation } from '../shared/utils'; -import { FireworksApiFields } from './FireworksApiField'; -import { - MemeooorrFieldValues, - useMemeFormValidate, -} from './useMemeFormValidate'; - -const { Title, Text } = Typography; - -type MemeooorrFormValues = MemeooorrFieldValues & { - fireworksApiEnabled: boolean; -}; - -export const XAccountCredentials = () => ( - - - - X account credentials - - - Create a new account for your agent at{' '} - - x.com - {' '} - and enter the login details. This enables your agent to view X and - interact with other agents. - - - - To avoid your X account getting suspended for bot activity, complete - the onboarding steps. You can find them on your profile page under - "Let‘s get you set up". - - - } - className="mb-16" - /> - -); - -export const InvalidXCredentials = () => ( - X account credentials are invalid or 2FA is enabled.} - className="mb-16" - /> -); - -type MemeooorrAgentFormProps = { serviceTemplate: ServiceTemplate }; - -export const MemeooorrAgentForm = ({ - serviceTemplate, -}: MemeooorrAgentFormProps) => { - const { goto } = useSetup(); - const { defaultStakingProgramId } = useStakingProgram(); - - const [form] = Form.useForm(); - const [isSubmitting, setIsSubmitting] = useState(false); - - const { - submitButtonText, - setSubmitButtonText, - geminiApiKeyValidationStatus, - setGeminiApiKeyValidationStatus, - twitterCredentialsValidationStatus, - setTwitterCredentialsValidationStatus, - validateForm, - } = useMemeFormValidate(); - - const onFinish = useCallback( - async (values: MemeooorrFormValues) => { - if (!defaultStakingProgramId) return; - - try { - setIsSubmitting(true); - - const cookies = await validateForm(values); - if (!cookies) return; - - const overriddenServiceConfig: ServiceTemplate = { - ...serviceTemplate, - description: `Memeooorr @${values.xUsername}`, - env_variables: { - ...serviceTemplate.env_variables, - TWIKIT_USERNAME: { - ...serviceTemplate.env_variables.TWIKIT_USERNAME, - value: values.xUsername, - }, - TWIKIT_EMAIL: { - ...serviceTemplate.env_variables.TWIKIT_EMAIL, - value: values.xEmail, - }, - TWIKIT_PASSWORD: { - ...serviceTemplate.env_variables.TWIKIT_PASSWORD, - value: values.xPassword, - }, - TWIKIT_COOKIES: { - ...serviceTemplate.env_variables.TWIKIT_COOKIES, - value: cookies, - }, - GENAI_API_KEY: { - ...serviceTemplate.env_variables.GENAI_API_KEY, - value: values.geminiApiKey, - }, - FIREWORKS_API_KEY: { - ...serviceTemplate.env_variables.FIREWORKS_API_KEY, - value: values.fireworksApiEnabled ? values.fireworksApiKey : '', - }, - PERSONA: { - ...serviceTemplate.env_variables.PERSONA, - value: values.personaDescription, - }, - }, - }; - - await onDummyServiceCreation( - defaultStakingProgramId, - overriddenServiceConfig, - ); - - message.success('Agent setup complete'); - - // move to next page - goto(SetupScreen.SetupEoaFunding); - } catch (error) { - message.error('Something went wrong. Please try again.'); - console.error(error); - } finally { - setIsSubmitting(false); - setSubmitButtonText('Continue'); - } - }, - [ - defaultStakingProgramId, - validateForm, - serviceTemplate, - goto, - setSubmitButtonText, - ], - ); - - // Clean up - useUnmount(async () => { - setIsSubmitting(false); - setGeminiApiKeyValidationStatus('unknown'); - setTwitterCredentialsValidationStatus('unknown'); - setSubmitButtonText('Continue'); - }); - - const canSubmitForm = isSubmitting || !defaultStakingProgramId; - - return ( - <> - - Provide your agent with a persona, access to an LLM and an X account. - - - - - form={form} - name="setup-your-agent" - layout="vertical" - onFinish={onFinish} - validateMessages={emailValidateMessages} - disabled={canSubmitForm} - > - - - - - - - - {geminiApiKeyValidationStatus === 'invalid' && ( - - )} - - - - {/* X */} - - {twitterCredentialsValidationStatus === 'invalid' && ( - - )} - - - - - - - { - if (e.key === '@') { - e.preventDefault(); - } - }} - /> - - - { - if (value && value.includes('$')) { - return Promise.reject( - new Error( - 'Password must not contain the “$” symbol. Please update your password on Twitter, then retry.', - ), - ); - } - return Promise.resolve(); - }, - }, - ]} - > - - - - - - - - - ); -}; diff --git a/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/useMemeFormValidate.ts b/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/useMemeFormValidate.ts deleted file mode 100644 index fa43cba5b..000000000 --- a/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentForm/useMemeFormValidate.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { useCallback, useState } from 'react'; - -import { useElectronApi } from '@/hooks/useElectronApi'; - -import { - validateGeminiApiKey, - validateTwitterCredentials, - ValidationStatus, -} from '../shared/validations'; - -export type MemeooorrFieldValues = { - personaDescription: string; - geminiApiKey: string; - fireworksApiKey: string; - xEmail: string; - xUsername: string; - xPassword: string; -}; - -export const useMemeFormValidate = () => { - const electronApi = useElectronApi(); - - const [isValidating, setIsValidating] = useState(false); - const [submitButtonText, setSubmitButtonText] = useState('Continue'); - const [geminiApiKeyValidationStatus, setGeminiApiKeyValidationStatus] = - useState('unknown'); - const [ - twitterCredentialsValidationStatus, - setTwitterCredentialsValidationStatus, - ] = useState('unknown'); - - const handleValidate = useCallback( - async (values: MemeooorrFieldValues) => { - setIsValidating(true); - - setGeminiApiKeyValidationStatus('unknown'); - setTwitterCredentialsValidationStatus('unknown'); - setSubmitButtonText('Validating Gemini API key...'); - - try { - const isGeminiApiValid = await validateGeminiApiKey( - values.geminiApiKey, - ); - setGeminiApiKeyValidationStatus(isGeminiApiValid ? 'valid' : 'invalid'); - if (!isGeminiApiValid) return; - - // validate the twitter credentials - setSubmitButtonText('Validating Twitter credentials...'); - const { isValid: isTwitterCredentialsValid, cookies } = - electronApi?.validateTwitterLogin - ? await validateTwitterCredentials( - values.xEmail, - values.xUsername, - values.xPassword, - electronApi.validateTwitterLogin, - ) - : { isValid: false, cookies: undefined }; - setTwitterCredentialsValidationStatus( - isTwitterCredentialsValid ? 'valid' : 'invalid', - ); - if (!isTwitterCredentialsValid) return; - if (!cookies) return; - - // wait for agent setup to complete - setSubmitButtonText('Setting up agent...'); - - return cookies; - } catch (error) { - console.error('Error validating meme form:', error); - } finally { - setIsValidating(false); - } - }, - [electronApi.validateTwitterLogin], - ); - - return { - isValidating, - submitButtonText, - setSubmitButtonText, - geminiApiKeyValidationStatus, - setGeminiApiKeyValidationStatus, - twitterCredentialsValidationStatus, - setTwitterCredentialsValidationStatus, - validateForm: handleValidate, - }; -}; diff --git a/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentSetup.tsx b/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentSetup.tsx new file mode 100644 index 000000000..fbee4c48b --- /dev/null +++ b/frontend/components/SetupPage/SetupYourAgent/MemeooorrAgentSetup.tsx @@ -0,0 +1,101 @@ +import { Divider, message, Typography } from 'antd'; +import React, { useCallback } from 'react'; + +import { ServiceTemplate } from '@/client'; +import { SetupScreen } from '@/enums/SetupScreen'; +import { useSetup } from '@/hooks/useSetup'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; +import { onDummyServiceCreation } from '@/utils/service'; + +import { + MemeooorrAgentForm, + MemeooorrFormValues, +} from '../../AgentForms/MemeooorrAgentForm'; + +const { Text } = Typography; + +type MemeooorrAgentFormProps = { serviceTemplate: ServiceTemplate }; + +export const MemeooorrAgentSetup = ({ + serviceTemplate, +}: MemeooorrAgentFormProps) => { + const { goto } = useSetup(); + const { defaultStakingProgramId } = useStakingProgram(); + + const onSubmit = useCallback( + async (values: MemeooorrFormValues & { fireworksApiEnabled: boolean }) => { + if (!defaultStakingProgramId) return; + + try { + const overriddenServiceConfig: ServiceTemplate = { + ...serviceTemplate, + description: `Memeooorr @${values.xUsername}`, + env_variables: { + ...serviceTemplate.env_variables, + TWEEPY_CONSUMER_API_KEY: { + ...serviceTemplate.env_variables.TWEEPY_CONSUMER_API_KEY, + value: values.xConsumerApiKey, + }, + TWEEPY_CONSUMER_API_KEY_SECRET: { + ...serviceTemplate.env_variables.TWEEPY_CONSUMER_API_KEY_SECRET, + value: values.xConsumerApiSecret, + }, + TWEEPY_BEARER_TOKEN: { + ...serviceTemplate.env_variables.TWEEPY_BEARER_TOKEN, + value: values.xBearerToken, + }, + TWEEPY_ACCESS_TOKEN: { + ...serviceTemplate.env_variables.TWEEPY_ACCESS_TOKEN, + value: values.xAccessToken, + }, + TWEEPY_ACCESS_TOKEN_SECRET: { + ...serviceTemplate.env_variables.TWEEPY_ACCESS_TOKEN_SECRET, + value: values.xAccessTokenSecret, + }, + GENAI_API_KEY: { + ...serviceTemplate.env_variables.GENAI_API_KEY, + value: values.geminiApiKey, + }, + FIREWORKS_API_KEY: { + ...serviceTemplate.env_variables.FIREWORKS_API_KEY, + value: values.fireworksApiEnabled ? values.fireworksApiKey : '', + }, + PERSONA: { + ...serviceTemplate.env_variables.PERSONA, + value: values.personaDescription, + }, + }, + }; + + await onDummyServiceCreation( + defaultStakingProgramId, + overriddenServiceConfig, + ); + + message.success('Agent setup complete'); + + // move to next page + goto(SetupScreen.SetupEoaFunding); + } catch (error) { + message.error('Something went wrong. Please try again.'); + console.error(error); + } + }, + [defaultStakingProgramId, serviceTemplate, goto], + ); + + return ( + <> + + Provide your agent with a persona, access to an LLM and an X account. + + + + + + ); +}; diff --git a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx b/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx index 18eedc357..9715ddf23 100644 --- a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx +++ b/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx @@ -7,6 +7,7 @@ import { COINGECKO_URL, TENDERLY_URL } from '@/constants/urls'; import { SetupScreen } from '@/enums/SetupScreen'; import { useSetup } from '@/hooks/useSetup'; import { useStakingProgram } from '@/hooks/useStakingProgram'; +import { onDummyServiceCreation } from '@/utils/service'; import { agentFieldProps, @@ -14,16 +15,15 @@ import { validateApiKey, validateMessages, validateSlug, -} from '../shared/formUtils'; -import { InvalidGeminiApiCredentials } from '../shared/InvalidGeminiApiCredentials'; +} from '../../../AgentForms/common/formUtils'; +import { InvalidGeminiApiCredentials } from '../../../AgentForms/common/InvalidGeminiApiCredentials'; import { CoinGeckoApiKeyLabel, ModiusGeminiApiKeyLabel, TenderlyAccessTokenLabel, TenderlyAccountSlugLabel, TenderlyProjectSlugLabel, -} from '../shared/labels'; -import { onDummyServiceCreation } from '../shared/utils'; +} from '../../../AgentForms/common/labels'; import { ModiusFieldValues, useModiusFormValidate, diff --git a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/useModiusFormValidate.ts b/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/useModiusFormValidate.ts index 2e5855753..26a9949f1 100644 --- a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/useModiusFormValidate.ts +++ b/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/useModiusFormValidate.ts @@ -1,6 +1,9 @@ import { useCallback, useState } from 'react'; -import { validateGeminiApiKey, ValidationStatus } from '../shared/validations'; +import { + validateGeminiApiKey, + ValidationStatus, +} from '../../../AgentForms/common/validations'; export type ModiusFieldValues = { tenderlyAccessToken: string; diff --git a/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx index 70035aaf2..c92922057 100644 --- a/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx +++ b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx @@ -7,6 +7,7 @@ import { COINGECKO_URL, TENDERLY_URL } from '@/constants/urls'; import { SetupScreen } from '@/enums/SetupScreen'; import { useSetup } from '@/hooks/useSetup'; import { useStakingProgram } from '@/hooks/useStakingProgram'; +import { onDummyServiceCreation } from '@/utils/service'; import { agentFieldProps, @@ -14,16 +15,15 @@ import { validateApiKey, validateMessages, validateSlug, -} from '../shared/formUtils'; -import { InvalidGeminiApiCredentials } from '../shared/InvalidGeminiApiCredentials'; +} from '../../../AgentForms/common/formUtils'; +import { InvalidGeminiApiCredentials } from '../../../AgentForms/common/InvalidGeminiApiCredentials'; import { CoinGeckoApiKeyLabel, OptimusGeminiApiKeyLabel, TenderlyAccessTokenLabel, TenderlyAccountSlugLabel, TenderlyProjectSlugLabel, -} from '../shared/labels'; -import { onDummyServiceCreation } from '../shared/utils'; +} from '../../../AgentForms/common/labels'; import { OptimusFieldValues, useOptimusFormValidate, diff --git a/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate.ts b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate.ts index 607882937..b9ef9fb4e 100644 --- a/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate.ts +++ b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/useOptimusFormValidate.ts @@ -1,6 +1,9 @@ import { useCallback, useState } from 'react'; -import { validateGeminiApiKey, ValidationStatus } from '../shared/validations'; +import { + validateGeminiApiKey, + ValidationStatus, +} from '../../../AgentForms/common/validations'; export type OptimusFieldValues = { tenderlyAccessToken: string; diff --git a/frontend/components/SetupPage/SetupYourAgent/SetupYourAgent.tsx b/frontend/components/SetupPage/SetupYourAgent/SetupYourAgent.tsx index 60c7f9da8..31dcdd47b 100644 --- a/frontend/components/SetupPage/SetupYourAgent/SetupYourAgent.tsx +++ b/frontend/components/SetupPage/SetupYourAgent/SetupYourAgent.tsx @@ -10,7 +10,7 @@ import { useServices } from '@/hooks/useServices'; import { LOCAL_FORM_THEME } from '@/theme'; import { SetupCreateHeader } from '../Create/SetupCreateHeader'; -import { MemeooorrAgentForm } from './MemeooorrAgentForm/MemeooorrAgentForm'; +import { MemeooorrAgentSetup } from './MemeooorrAgentSetup'; import { ModiusAgentForm } from './ModiusAgentForm/ModiusAgentForm'; import { OptimusAgentForm } from './OptimusAgentForm/OptimusAgentForm'; @@ -37,10 +37,12 @@ export const SetupYourAgent = () => { - Set up your agent + + Set up your agent + {selectedAgentType === AgentType.Memeooorr && ( - + )} {selectedAgentType === AgentType.Modius && ( diff --git a/frontend/components/SetupPage/SetupYourAgent/shared/utils.ts b/frontend/components/SetupPage/SetupYourAgent/shared/utils.ts deleted file mode 100644 index a7d6138d9..000000000 --- a/frontend/components/SetupPage/SetupYourAgent/shared/utils.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { ServiceTemplate } from '@/client'; -import { StakingProgramId } from '@/enums/StakingProgram'; -import { ServicesService } from '@/service/Services'; - -export const onDummyServiceCreation = async ( - stakingProgramId: StakingProgramId, - serviceTemplateConfig: ServiceTemplate, -) => { - await ServicesService.createService({ - serviceTemplate: serviceTemplateConfig, - deploy: true, - stakingProgramId, - }); -}; diff --git a/frontend/components/SetupPage/SetupYourAgent/shared/validations.ts b/frontend/components/SetupPage/SetupYourAgent/shared/validations.ts deleted file mode 100644 index 3813e5cc5..000000000 --- a/frontend/components/SetupPage/SetupYourAgent/shared/validations.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { XCookie } from '@/types/Cookies'; - -export type ValidationStatus = 'valid' | 'invalid' | 'unknown'; - -/** - * Validate the Google Gemini API key - */ -export const validateGeminiApiKey = async (apiKey: string) => { - if (!apiKey) return false; - - try { - // sample request to fetch the models - const apiUrl = - 'https://generativelanguage.googleapis.com/v1/models?key=' + apiKey; - const response = await fetch(apiUrl); - - return response.ok; - } catch (error) { - console.error('Error validating Gemini API key:', error); - return false; - } -}; - -const formatXCookies = (cookiesArray: XCookie[]) => { - const cookiesObject: Record = {}; - cookiesArray.forEach((cookie) => { - cookiesObject[cookie.key] = cookie.value; - }); - return JSON.stringify(cookiesObject); -}; - -/** - * Validate the Twitter credentials - */ -export const validateTwitterCredentials = async ( - email: string, - username: string, - password: string, - validateTwitterLogin: ({ - username, - password, - email, - }: { - email: string; - username: string; - password: string; - }) => Promise<{ success: boolean; cookies?: XCookie[] }>, -): Promise<{ isValid: boolean; cookies?: string }> => { - if (!email || !username || !password) return { isValid: false }; - - try { - const result = await validateTwitterLogin({ - username, - password, - email, - }); - - const cookies = result.cookies; - - if (cookies) { - return { isValid: true, cookies: formatXCookies(cookies) }; - } - - console.error('Error validating Twitter credentials:', result); - return { isValid: false }; - } catch (error) { - console.error('Unexpected error validating Twitter credentials:', error); - return { isValid: false }; - } -}; diff --git a/frontend/components/SetupPage/index.tsx b/frontend/components/SetupPage/index.tsx index 515e28184..908a934ba 100644 --- a/frontend/components/SetupPage/index.tsx +++ b/frontend/components/SetupPage/index.tsx @@ -1,11 +1,14 @@ +import { Typography } from 'antd'; import { useContext, useMemo } from 'react'; import { SetupContext } from '@/context/SetupProvider'; import { SetupScreen } from '@/enums/SetupScreen'; import { AgentSelection } from '../AgentSelection'; +import { CardFlex } from '../styled/CardFlex'; import { AgentIntroduction } from './AgentIntroduction/AgentIntroduction'; import { SetupBackupSigner } from './Create/SetupBackupSigner'; +import { SetupBridgeOnboarding } from './Create/SetupBridgeOnboarding/SetupBridgeOnboarding'; import { SetupCreateSafe } from './Create/SetupCreateSafe'; import { SetupEoaFunding } from './Create/SetupEoaFunding'; import { SetupPassword } from './Create/SetupPassword'; @@ -20,8 +23,14 @@ import { import { SetupWelcome } from './SetupWelcome'; import { SetupYourAgent } from './SetupYourAgent/SetupYourAgent'; +const { Title } = Typography; + const UnexpectedError = () => ( -
      Something went wrong!
      + + + Something went wrong! + + ); export const Setup = () => { @@ -54,6 +63,10 @@ export const Setup = () => { case SetupScreen.SetupYourAgent: return ; + // Bridge account + case SetupScreen.SetupBridgeOnboardingScreen: + return ; + // Restore account case SetupScreen.Restore: return ; diff --git a/frontend/components/UpdateAgentPage/MemeooorrUpdatePage.tsx b/frontend/components/UpdateAgentPage/MemeooorrUpdatePage.tsx deleted file mode 100644 index 202342000..000000000 --- a/frontend/components/UpdateAgentPage/MemeooorrUpdatePage.tsx +++ /dev/null @@ -1,250 +0,0 @@ -import { Button, Form, Input } from 'antd'; -import { get, isEqual, omit } from 'lodash'; -import { useCallback, useContext, useMemo } from 'react'; - -import { Pages } from '@/enums/Pages'; -import { usePageState } from '@/hooks/usePageState'; -import { useServices } from '@/hooks/useServices'; -import { Nullable } from '@/types/Util'; - -import { FireworksApiFields } from '../SetupPage/SetupYourAgent/MemeooorrAgentForm/FireworksApiField'; -import { - InvalidXCredentials, - XAccountCredentials, -} from '../SetupPage/SetupYourAgent/MemeooorrAgentForm/MemeooorrAgentForm'; -// TODO: move the following hook/components to a shared place -// once Modius work is merged -import { useMemeFormValidate } from '../SetupPage/SetupYourAgent/MemeooorrAgentForm/useMemeFormValidate'; -import { - commonFieldProps, - requiredRules, - validateMessages, -} from '../SetupPage/SetupYourAgent/shared/formUtils'; -import { InvalidGeminiApiCredentials } from '../SetupPage/SetupYourAgent/shared/InvalidGeminiApiCredentials'; -import { CardLayout } from './CardLayout'; -import { UpdateAgentContext } from './context/UpdateAgentProvider'; - -type MemeooorrFormValues = { - description: string; - fireworksApiEnabled: boolean; - env_variables: { - GENAI_API_KEY: string; - FIREWORKS_API_KEY: string; - PERSONA: string; - TWIKIT_USERNAME: string; - TWIKIT_EMAIL: string; - TWIKIT_PASSWORD: string; - TWIKIT_COOKIES: string; - }; -}; - -type MemeUpdateFormProps = { - initialFormValues: Nullable; -}; - -const MemeUpdateForm = ({ initialFormValues }: MemeUpdateFormProps) => { - const { - isEditing, - form, - confirmUpdateModal: confirmModal, - } = useContext(UpdateAgentContext); - - const { - isValidating, - geminiApiKeyValidationStatus, - twitterCredentialsValidationStatus, - validateForm, - } = useMemeFormValidate(); - - const handleFinish = async (values: MemeooorrFormValues) => { - const cookies = await validateForm({ - personaDescription: values.env_variables.PERSONA, - geminiApiKey: values.env_variables.GENAI_API_KEY, - fireworksApiKey: values.fireworksApiEnabled - ? values.env_variables.FIREWORKS_API_KEY - : '', - xEmail: values.env_variables.TWIKIT_EMAIL, - xUsername: values.env_variables.TWIKIT_USERNAME, - xPassword: values.env_variables.TWIKIT_PASSWORD, - }); - if (!cookies) return; - - // fields for firework api key - form?.setFieldValue( - ['env_variables', 'FIREWORKS_API_KEY'], - values.fireworksApiEnabled ? values.env_variables.FIREWORKS_API_KEY : '', - ); - - // other fields - form?.setFieldValue(['env_variables', 'TWIKIT_COOKIES'], cookies); - form?.setFieldValue( - 'description', - `Memeooorr @${values.env_variables.TWIKIT_USERNAME}`, - ); - - confirmModal.openModal(); - }; - - return ( - - form={form} - layout="vertical" - disabled={!isEditing} - variant={isEditing ? 'outlined' : 'borderless'} - onFinish={handleFinish} - validateMessages={validateMessages} - initialValues={{ ...initialFormValues }} - > - - - - - {/* Gemini credentials */} - - - - {geminiApiKeyValidationStatus === 'invalid' && ( - - )} - - {/* Fireworks API */} - - - {/* X */} - - {twitterCredentialsValidationStatus === 'invalid' && ( - - )} - - - - - { - if (e.key === '@') { - e.preventDefault(); - } - }} - /> - - { - if (value && value.includes('$')) { - return Promise.reject( - new Error( - 'Password must not contain the “$” symbol. Please update your password on Twitter, then retry.', - ), - ); - } - return Promise.resolve(); - }, - }, - ]} - > - - - - {/* Hidden fields that need to be accessible in Confirm Update Modal */} -
      + ); +}; diff --git a/frontend/components/bridge/BridgeTransferFlow.tsx b/frontend/components/bridge/BridgeTransferFlow.tsx new file mode 100644 index 000000000..c2d88523c --- /dev/null +++ b/frontend/components/bridge/BridgeTransferFlow.tsx @@ -0,0 +1,83 @@ +import { ArrowRightOutlined } from '@ant-design/icons'; +import { Flex, List, Typography } from 'antd'; +import { kebabCase } from 'lodash'; +import Image from 'next/image'; +import React from 'react'; + +import { COLOR } from '@/constants/colors'; +import { CrossChainTransferDetails, TokenTransfer } from '@/types/Bridge'; +import { formatUnitsToNumber } from '@/utils/numberFormatters'; + +const { Text } = Typography; + +const TransferChain = ({ chainName }: { chainName: string }) => ( + + chain logo + {chainName} + +); + +const TransferringAndReceivingRow = () => ( + + + Transferring + Receiving + + +); + +const TransferRow = ({ transfer }: { transfer: TokenTransfer }) => { + const { fromAmount, fromSymbol, toSymbol, toAmount, decimals } = transfer; + return ( + + + + {formatUnitsToNumber(fromAmount, decimals, 5)} {fromSymbol} + + + {formatUnitsToNumber(toAmount, decimals, 5)} {toSymbol} + + + + ); +}; + +type BridgeTransferFlowProps = CrossChainTransferDetails; + +/** + * Presentational component for the bridge transfer flow + * showing the transfer details between two chains. + */ +export const BridgeTransferFlow = ({ + fromChain, + toChain, + transfers, +}: BridgeTransferFlowProps) => { + return ( + + + + + + } + renderItem={(transfer, index) => ( + <> + {index === 0 && } + + + )} + bordered + size="small" + /> + ); +}; diff --git a/frontend/components/bridge/BridgingSteps.tsx b/frontend/components/bridge/BridgingSteps.tsx new file mode 100644 index 000000000..5e7bbcafb --- /dev/null +++ b/frontend/components/bridge/BridgingSteps.tsx @@ -0,0 +1,240 @@ +import { LoadingOutlined } from '@ant-design/icons'; +import { Button, Flex, Steps, Typography } from 'antd'; +import React, { useMemo } from 'react'; +import styled from 'styled-components'; + +import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { SUPPORT_URL } from '@/constants/urls'; +import { TokenSymbol } from '@/enums/Token'; +import { BridgingStepStatus as Status } from '@/types/Bridge'; +import { Maybe, Nullable } from '@/types/Util'; + +import { ExportLogsButton } from '../ExportLogsButton'; + +const { Text } = Typography; + +const SubStepRow = styled.div` + line-height: normal; +`; + +const Desc = ({ text }: { text: string }) => ( + + {text} + +); + +const TxnDetails = ({ link }: { link: string }) => ( + + + Txn details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + +); + +type FundsAreSafeMessageProps = Pick; +const FundsAreSafeMessage = ({ + onRetry, + onRetryProps, +}: FundsAreSafeMessageProps) => ( + + + {onRetry && ( + + )} + + + + + Don't worry, your funds remain safe. You can access them by importing + your Pearl seed phrase into a compatible wallet, like MetaMask or + Coinbase. + + + + Ask for help in{' '} + + the Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + + + You can also try restarting the app! + + +); + +type Step = { + title: string; + status: Status; + computedSubSteps: { + description: Nullable; + txnLink: Maybe; + isFailed?: boolean; + onRetry?: () => void; + onRetryProps?: { isLoading: boolean }; + }[]; +}; + +export type StepEvent = { + symbol?: TokenSymbol; + status?: Status; + txnLink?: Maybe; + onRetry?: () => void; + onRetryProps?: { isLoading: boolean }; +}; + +const generateBridgeStep = ( + status: Status, + subSteps: StepEvent[], +): Omit => { + return { + status, + computedSubSteps: subSteps.map( + ({ symbol, status, txnLink, onRetry, onRetryProps }) => { + const isFailed = status === 'error'; + const description = (() => { + if (status === 'finish') { + return `Bridging ${symbol || ''} transaction complete.`; + } + if (status === 'error') { + return `Bridging ${symbol || ''} failed.`; + } + return `Sending transaction...`; + })(); + + return { description, txnLink, isFailed, onRetry, onRetryProps }; + }, + ), + }; +}; + +const generateMasterSafeCreationStep = ( + status: Status, + subSteps: StepEvent[], +): Step => { + const isFailed = status === 'error'; + const description = (() => { + if (status === 'finish') return 'Transaction complete.'; + if (status === 'error') return 'Transaction failed.'; + if (status === 'process') return 'Sending transaction...'; + return null; + })(); + + return { + title: 'Create Master Safe', + status, + computedSubSteps: subSteps.map(({ txnLink }) => { + return { description, txnLink, isFailed }; + }), + }; +}; + +const generateMasterSafeTransferStep = ( + status: Status, + subSteps: StepEvent[], +): Step => { + return { + title: 'Transfer funds to the Master Safe', + status, + computedSubSteps: subSteps.map(({ symbol, status, txnLink }) => { + const isFailed = status === 'error'; + const description = (() => { + if (status === 'finish') { + return `Transfer ${symbol} transaction complete.`; + } + if (status === 'process') { + return 'Sending transaction...'; + } + if (status === 'error') { + return `Transfer ${symbol} transaction failed.`; + } + return null; + })(); + + return { description, txnLink, isFailed }; + }), + }; +}; + +type BridgingStep = { status: Status; subSteps: StepEvent[] }; + +type BridgingStepsProps = { + chainName: string; + bridge: BridgingStep; + masterSafeCreation?: BridgingStep; + masterSafeTransfer?: BridgingStep; +}; + +/** + * Presentational component for the bridging steps. + */ +export const BridgingSteps = ({ + chainName, + bridge, + masterSafeCreation, + masterSafeTransfer, +}: BridgingStepsProps) => { + const bridgeStep: Step = useMemo(() => { + return { + title: `Bridge funds to ${chainName}`, + ...generateBridgeStep(bridge.status, bridge.subSteps), + }; + }, [chainName, bridge]); + + const masterSafeCreationStep: Nullable = useMemo(() => { + if (!masterSafeCreation) return null; + return generateMasterSafeCreationStep( + masterSafeCreation.status, + masterSafeCreation.subSteps, + ); + }, [masterSafeCreation]); + + const masterSafeTransferStep: Nullable = useMemo(() => { + if (!masterSafeTransfer) return null; + return generateMasterSafeTransferStep( + masterSafeTransfer.status, + masterSafeTransfer.subSteps, + ); + }, [masterSafeTransfer]); + + const steps = useMemo( + () => + [bridgeStep, masterSafeCreationStep, masterSafeTransferStep].filter( + (step): step is Step => Boolean(step), + ), + [bridgeStep, masterSafeCreationStep, masterSafeTransferStep], + ); + + return ( + { + return { + status, + title, + description: computedSubSteps.map((subStep, index) => ( + + {subStep.description && } + {subStep.txnLink && } + {subStep.isFailed && ( + + )} + + )), + icon: status === 'process' ? : undefined, + }; + })} + /> + ); +}; diff --git a/frontend/components/bridge/DepositAddress.tsx b/frontend/components/bridge/DepositAddress.tsx new file mode 100644 index 000000000..4a26f05d6 --- /dev/null +++ b/frontend/components/bridge/DepositAddress.tsx @@ -0,0 +1,42 @@ +import { CopyOutlined } from '@ant-design/icons'; +import { Button, Flex, message, Tooltip, Typography } from 'antd'; +import { useCallback } from 'react'; + +import { useMasterWalletContext } from '@/hooks/useWallet'; +import { copyToClipboard } from '@/utils/copyToClipboard'; + +import { LIGHT_ICON_STYLE } from '../ui/iconStyles'; + +const { Text } = Typography; + +// TODO: make a shared component similar to AccountCreationAddress +export const DepositAddress = () => { + const { masterEoa } = useMasterWalletContext(); + const address = masterEoa?.address; + + const handleCopyAddress = useCallback(() => { + if (address) { + copyToClipboard(address).then(() => message.success('Address copied!')); + } + }, [address]); + + return ( + + + + Deposit address + + + + + +); + +type DepositForBridgingProps = { + chainName: string; + updateQuoteId: (quoteId: string) => void; + updateCrossChainTransferDetails: (details: CrossChainTransferDetails) => void; + onNext: () => void; +}; + +export const DepositForBridging = ({ + chainName, + updateQuoteId, + updateCrossChainTransferDetails, + onNext, +}: DepositForBridgingProps) => { + const { selectedAgentConfig } = useServices(); + const toMiddlewareChain = selectedAgentConfig.middlewareHomeChainId; + const { masterEoa } = useMasterWalletContext(); + const { refillRequirements, isBalancesAndFundingRequirementsLoading } = + useBalanceAndRefillRequirementsContext(); + const getBridgeRequirementsParams = useGetBridgeRequirementsParams(); + + const [ + isBridgeRefillRequirementsApiLoading, + setIsBridgeRefillRequirementsApiLoading, + ] = useState(true); + const [isForceUpdate, setIsForceUpdate] = useState(false); + const [ + canPollForBridgeRefillRequirements, + setCanPollForBridgeRefillRequirements, + ] = useState(true); + + const bridgeRequirementsParams = useMemo(() => { + if (!getBridgeRequirementsParams) return null; + return getBridgeRequirementsParams(isForceUpdate); + }, [isForceUpdate, getBridgeRequirementsParams]); + + // force_update: true is used only when the user clicks on "Try again", + // hence reset it to false after the API call is made. + const resetForceUpdate = useCallback(() => setIsForceUpdate(false), []); + + const { + data: bridgeFundingRequirements, + isLoading: isBridgeRefillRequirementsLoading, + isError: isBridgeRefillRequirementsError, + isFetching: isBridgeRefillRequirementsFetching, + refetch: refetchBridgeRefillRequirements, + } = useBridgeRefillRequirements( + bridgeRequirementsParams, + canPollForBridgeRefillRequirements, + isForceUpdate ? resetForceUpdate : undefined, + ); + + // fetch bridge refill requirements manually on mount + useEffect(() => { + if (!isBridgeRefillRequirementsApiLoading) return; + + refetchBridgeRefillRequirements().finally(() => { + setIsBridgeRefillRequirementsApiLoading(false); + }); + }, [ + isBridgeRefillRequirementsApiLoading, + refetchBridgeRefillRequirements, + setIsBridgeRefillRequirementsApiLoading, + ]); + + const isRequestingQuote = + isBalancesAndFundingRequirementsLoading || + isBridgeRefillRequirementsApiLoading || + isBridgeRefillRequirementsLoading; + + const isRequestingQuoteFailed = useMemo(() => { + if (isRequestingQuote) return false; + if (isBridgeRefillRequirementsError) return true; + + // Even if the API call succeeds, if any entry has QUOTE_FAILED, + // we should still display an error message and allow the user to retry. + return bridgeFundingRequirements?.bridge_request_status.some( + (request) => request.status === 'QUOTE_FAILED', + ); + }, [ + isRequestingQuote, + isBridgeRefillRequirementsError, + bridgeFundingRequirements, + ]); + + // If quote has failed, stop polling for bridge refill requirements + useEffect(() => { + if (!isRequestingQuoteFailed) return; + setCanPollForBridgeRefillRequirements(false); + }, [isRequestingQuoteFailed]); + + // List of tokens that need to be deposited + const tokens = useMemo(() => { + if (!bridgeFundingRequirements) return []; + if (!masterEoa) return []; + + const fromMiddlewareChain = MiddlewareChain.ETHEREUM; + + const bridgeTotalRequirements = + bridgeFundingRequirements.bridge_total_requirements[ + fromMiddlewareChain + ]?.[masterEoa.address]; + const bridgeRefillRequirements = + bridgeFundingRequirements.bridge_refill_requirements[ + fromMiddlewareChain + ]?.[masterEoa.address]; + + if (!bridgeTotalRequirements || !bridgeRefillRequirements) return []; + + const totalRequirements = Object.entries(bridgeTotalRequirements); + return totalRequirements.map(([tokenAddress, totalRequired]) => { + const totalRequiredInWei = BigInt(totalRequired); + + // current balance = total_required_amount - required_amount + // eg. if total_required_amount = 1000 and required_amount = 200, + // then the assumed current_balance = 1000 - 200 = 800 + const currentBalanceInWei = + totalRequiredInWei - + BigInt(bridgeRefillRequirements[tokenAddress as Address] || 0); + + const token = Object.values(ETHEREUM_TOKEN_CONFIG).find((tokenInfo) => { + if (tokenAddress === AddressZero && !tokenInfo.address) return true; + return areAddressesEqual(tokenInfo.address!, tokenAddress); + }); + + if (!token) { + throw new Error( + `Failed to get the token info for the following token address: ${tokenAddress}`, + ); + } + + const areFundsReceived = totalRequiredInWei - currentBalanceInWei <= 0; + + return { + address: tokenAddress as Address, + symbol: token.symbol, + totalRequiredInWei, + currentBalanceInWei, + areFundsReceived, + decimals: token.decimals, + isNative: token.tokenType === TokenType.NativeGas, + } satisfies DepositTokenDetails; + }); + }, [bridgeFundingRequirements, masterEoa]); + + // After the user has deposited the required funds, + // send the quote ID, cross-chain transfer details to the next step + useEffect(() => { + if (isRequestingQuote) return; + if (isBridgeRefillRequirementsFetching) return; + if (!bridgeFundingRequirements) return; + if (tokens.length === 0) return; + if (isRequestingQuoteFailed) return; + if (!masterEoa?.address) return; + + const areAllFundsReceived = + tokens.every((token) => token.areFundsReceived) && + !bridgeFundingRequirements.is_refill_required; + if (!areAllFundsReceived) return; + updateQuoteId(bridgeFundingRequirements.id); + updateCrossChainTransferDetails({ + fromChain: upperFirst(MiddlewareChain.ETHEREUM), + toChain: upperFirst(toMiddlewareChain), + transfers: tokens.map((token) => { + const toAmount = (() => { + // TODO: reuse getFromToken function from utils.ts + + // Find the token address on the destination chain. + // eg. if the token is USDC on Ethereum, it will be USDC on Base + // but the address will be different. + const chainTokenConfig = + TOKEN_CONFIG[asEvmChainId(toMiddlewareChain)][token.symbol]; + const toTokenAddress = + token.symbol === TokenSymbol.ETH + ? token.address + : chainTokenConfig.address; + + if (!toTokenAddress) return BigInt(0); + + const toToken = bridgeRequirementsParams?.bridge_requests?.find( + ({ to }) => areAddressesEqual(to.token, toTokenAddress), + ); + if (!toToken) return BigInt(0); + + return BigInt(toToken.to.amount); + })(); + + return { + fromSymbol: token.symbol, + fromAmount: token.currentBalanceInWei.toString(), + toSymbol: token.symbol, + toAmount: toAmount.toString(), + decimals: token.decimals, + }; + }), + }); + + // wait for 2 seconds before proceeding to the next step. + message.success({ + content: 'Funds received, proceeding to next step...', + key: FUNDS_RECEIVED_MESSAGE_KEY, + }); + delayInSeconds(2).then(() => { + message.destroy(FUNDS_RECEIVED_MESSAGE_KEY); + onNext(); + }); + }, [ + isRequestingQuote, + isBridgeRefillRequirementsFetching, + isRequestingQuoteFailed, + toMiddlewareChain, + refillRequirements, + bridgeFundingRequirements, + masterEoa, + tokens, + bridgeRequirementsParams, + onNext, + updateQuoteId, + updateCrossChainTransferDetails, + ]); + + // Retry to fetch the bridge refill requirements + const handleRetryAgain = useCallback(() => { + setIsForceUpdate(true); + setCanPollForBridgeRefillRequirements(true); + }, []); + + return ( + + + + + {isRequestingQuote ? ( + + ) : isRequestingQuoteFailed ? ( + + ) : ( + <> + + {tokens.length === 0 ? ( + + No tokens to deposit! + + ) : ( + <> + {tokens.map((token) => ( + + ))} + + )} + + + + + )} + + ); +}; diff --git a/frontend/components/bridge/EstimatedCompletionTime.tsx b/frontend/components/bridge/EstimatedCompletionTime.tsx new file mode 100644 index 000000000..393de514f --- /dev/null +++ b/frontend/components/bridge/EstimatedCompletionTime.tsx @@ -0,0 +1,61 @@ +import { Flex, Skeleton, Statistic, Typography } from 'antd'; +import React, { useMemo } from 'react'; +import styled from 'styled-components'; + +const { Text } = Typography; +const { Countdown } = Statistic; + +const EstimatedTimeRow = styled(Flex)` + .ant-statistic .ant-statistic-content .ant-statistic-content-prefix { + margin-inline-end: 0 !important; + } + .ant-statistic .ant-statistic-content .ant-statistic-content-suffix { + margin-inline-start: 0 !important; + } +`; + +type EstimatedCompletionTimeProps = { + isLoading?: boolean; + timeInSeconds: number; +}; + +export const EstimatedCompletionTime = ({ + isLoading, + timeInSeconds, +}: EstimatedCompletionTimeProps) => { + const deadline = useMemo(() => { + if (!timeInSeconds) return 0; + return new Date(timeInSeconds * 1000).getTime(); + }, [timeInSeconds]); + + const minutesRemaining = useMemo(() => { + if (!deadline) return 0; + const minutes = Math.floor((deadline - new Date().getTime()) / 1000 / 60); + return Math.max(0, minutes); + }, [deadline]); + + return ( + + Estimated completion time: + {isLoading ? ( + + ) : ( + <> + + ~ {minutesRemaining} minute{minutesRemaining === 1 ? '' : 's'} + + + + + + )} + + ); +}; diff --git a/frontend/components/bridge/TokenDetails.tsx b/frontend/components/bridge/TokenDetails.tsx new file mode 100644 index 000000000..6c580c53c --- /dev/null +++ b/frontend/components/bridge/TokenDetails.tsx @@ -0,0 +1,95 @@ +import { CheckSquareOutlined, ClockCircleOutlined } from '@ant-design/icons'; +import { Divider, Flex, Typography } from 'antd'; + +import { TokenSymbol } from '@/enums/Token'; +import { Address } from '@/types/Address'; +import { formatUnitsToNumber } from '@/utils/numberFormatters'; + +import { InfoTooltip } from '../InfoTooltip'; +import { SUCCESS_ICON_STYLE, WARNING_ICON_STYLE } from '../ui/iconStyles'; + +const { Text } = Typography; + +export type DepositTokenDetails = { + address?: Address; + symbol: TokenSymbol; + totalRequiredInWei: bigint; + currentBalanceInWei: bigint; + areFundsReceived: boolean; + decimals: number; + isNative?: boolean; + precision?: number; +}; + +export const TokenDetails = ({ + symbol, + totalRequiredInWei, + currentBalanceInWei, + areFundsReceived, + decimals, + isNative, + precision = 2, +}: DepositTokenDetails) => { + const depositRequiredInWei = totalRequiredInWei - currentBalanceInWei; + + return ( + + {areFundsReceived ? ( + <> + + {symbol} funds received! + + ) : ( + <> + + + Waiting for{' '} + + {formatUnitsToNumber(depositRequiredInWei, decimals, precision)} +   + {symbol} + + + + )} + + + + + + Total amount required + + {`${formatUnitsToNumber(totalRequiredInWei, decimals, precision)} ${symbol}`} + + + + Balance at deposit address + + {`${formatUnitsToNumber(currentBalanceInWei, decimals, precision)} ${symbol}`} + + + + + Deposit required + + {`${formatUnitsToNumber(depositRequiredInWei, decimals, precision)} ${symbol}`} + + {isNative && ( + + The total amount may fluctuate due to periodic quote updates. + + )} + + + + ); +}; diff --git a/frontend/components/bridge/types.ts b/frontend/components/bridge/types.ts new file mode 100644 index 000000000..24a6aeae4 --- /dev/null +++ b/frontend/components/bridge/types.ts @@ -0,0 +1 @@ +export type SendFundAction = 'transfer' | 'bridge'; diff --git a/frontend/components/bridge/utils.ts b/frontend/components/bridge/utils.ts new file mode 100644 index 000000000..ef28fc420 --- /dev/null +++ b/frontend/components/bridge/utils.ts @@ -0,0 +1,216 @@ +import { isAddress } from 'ethers/lib/utils'; +import { useCallback } from 'react'; + +import { + AddressBalanceRecord, + MasterSafeBalanceRecord, + MiddlewareChain, +} from '@/client'; +import { + ChainTokenConfig, + ETHEREUM_TOKEN_CONFIG, + TOKEN_CONFIG, +} from '@/config/tokens'; +import { AddressZero } from '@/constants/address'; +import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; +import { useBalanceAndRefillRequirementsContext } from '@/hooks/useBalanceAndRefillRequirementsContext'; +import { useServices } from '@/hooks/useServices'; +import { useMasterWalletContext } from '@/hooks/useWallet'; +import { Address } from '@/types/Address'; +import { BridgeRefillRequirementsRequest } from '@/types/Bridge'; +import { areAddressesEqual } from '@/utils/address'; +import { bigintMax } from '@/utils/calculations'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; + +/** + * Helper to get source token address on the fromChain + */ +const getFromToken = ( + tokenAddress: string, + fromChainConfig: ChainTokenConfig, + toChainConfig: ChainTokenConfig, +): Address => { + if (tokenAddress.toLowerCase() === AddressZero) { + return AddressZero; + } + + const tokenSymbol = Object.values(toChainConfig).find((configToken) => + areAddressesEqual(configToken.address!, tokenAddress), + )?.symbol; + + if (!tokenSymbol || !fromChainConfig[tokenSymbol]?.address) { + throw new Error( + `Failed to get source token for the destination token: ${tokenAddress}`, + ); + } + + return fromChainConfig[tokenSymbol].address as Address; +}; + +/** + * + * @warning A HOOK THAT SHOULD NEVER EXIST. + * @deprecated TODO: This hook is used because BE doesn't support monthly_gas_estimate in the refill requirements yet. + * Remove the hook once it's supported + * + * Hook to return the updated bridge requirements params to improve the + * initial funding requirements. + * + * Request quote with formula (will be moved to backend): + * max(refill_requirement_masterSafe, monthly_gas_estimate) + refill_requirements_masterEOA + * + */ +const useGetBridgeRequirementsParamsWithMonthlyGasEstimate = () => { + const { selectedAgentConfig } = useServices(); + const { masterEoa } = useMasterWalletContext(); + const { refillRequirements, isBalancesAndFundingRequirementsLoading } = + useBalanceAndRefillRequirementsContext(); + + const toMiddlewareChain = selectedAgentConfig.middlewareHomeChainId; + + return useCallback( + (bridgeRequests: BridgeRefillRequirementsRequest['bridge_requests']) => { + if (isBalancesAndFundingRequirementsLoading) return; + if (!refillRequirements) return; + if (!masterEoa?.address) return; + + const nativeTokenIndex = bridgeRequests.findIndex((req) => + areAddressesEqual(req.from.token, AddressZero), + ); + if (nativeTokenIndex === -1) return; + + // refill_requirements_masterEOA + const masterEoaRequirementAmount = ( + refillRequirements as AddressBalanceRecord + )[masterEoa.address][AddressZero]; + + // refill_requirements_masterSafe + const safeRequirementAmount = ( + refillRequirements as MasterSafeBalanceRecord + )['master_safe'][AddressZero]; + + // monthly_gas_estimate + const monthlyGasEstimate = + SERVICE_TEMPLATES.find( + (template) => template.home_chain === toMiddlewareChain, + )?.configurations[toMiddlewareChain].monthly_gas_estimate ?? 0; + + // amount = max(refill_requirement_masterSafe, monthly_gas_estimate) + refill_requirements_masterEOA + const amount = + bigintMax(BigInt(safeRequirementAmount), BigInt(monthlyGasEstimate)) + + BigInt(masterEoaRequirementAmount); + + bridgeRequests[nativeTokenIndex].to.amount = amount.toString(); + + return bridgeRequests; + }, + [ + masterEoa, + refillRequirements, + toMiddlewareChain, + isBalancesAndFundingRequirementsLoading, + ], + ); +}; + +/** + * Helper to get bridge refill requirements parameters + * based on current refill requirements + */ +export const useGetBridgeRequirementsParams = () => { + const { selectedAgentConfig } = useServices(); + const { masterEoa } = useMasterWalletContext(); + const { refillRequirements, isBalancesAndFundingRequirementsLoading } = + useBalanceAndRefillRequirementsContext(); + const getUpdatedBridgeRequirementsParams = + useGetBridgeRequirementsParamsWithMonthlyGasEstimate(); + + const toMiddlewareChain = selectedAgentConfig.middlewareHomeChainId; + const fromAddress = masterEoa?.address; + const toAddress = masterEoa?.address; + + return useCallback( + (isForceUpdate = false) => { + if (isBalancesAndFundingRequirementsLoading) return null; + if (!refillRequirements) return null; + if (!fromAddress || !toAddress) return null; + + const fromChainConfig = ETHEREUM_TOKEN_CONFIG; // TODO: make dynamic, get from token config + const toChainConfig = TOKEN_CONFIG[asEvmChainId(toMiddlewareChain)]; + + const bridgeRequests: BridgeRefillRequirementsRequest['bridge_requests'] = + []; + + const tokensRefillList = Object.entries(refillRequirements); + + // Populate bridge requests from refill Requirements + for (const [walletAddress, tokensWithRequirements] of tokensRefillList) { + // Only calculate the refill requirements from master EOA or master safe placeholder + const isRecipientAddress = areAddressesEqual(walletAddress, toAddress); + if (!(isRecipientAddress || walletAddress === 'master_safe')) { + continue; + } + + for (const [tokenAddress, amount] of Object.entries( + tokensWithRequirements, + )) { + if (!isAddress(tokenAddress)) continue; + + const fromToken = getFromToken( + tokenAddress, + fromChainConfig, + toChainConfig, + ); + + const fromChain = MiddlewareChain.ETHEREUM; + const toChain = toMiddlewareChain; + const toToken = tokenAddress as Address; + + const existingRequest = bridgeRequests.find( + (req) => + req.from.chain === fromChain && + req.to.chain === toChain && + areAddressesEqual(req.from.address, fromAddress) && + areAddressesEqual(req.to.address, toAddress) && + areAddressesEqual(req.from.token, fromToken) && + areAddressesEqual(req.to.token, toToken), + ); + + if (existingRequest) { + // If the request already exists, update the amount + const toAmount = BigInt(existingRequest.to.amount) + BigInt(amount); + existingRequest.to.amount = toAmount.toString(); + } else { + bridgeRequests.push({ + from: { + chain: fromChain, + address: fromAddress, + token: fromToken, + }, + to: { + chain: toChain, + address: toAddress, + token: toToken, + amount: `${amount}`, + }, + }); + } + } + } + + return { + bridge_requests: + getUpdatedBridgeRequirementsParams(bridgeRequests) || bridgeRequests, + force_update: isForceUpdate, + } satisfies BridgeRefillRequirementsRequest; + }, + [ + fromAddress, + toAddress, + refillRequirements, + isBalancesAndFundingRequirementsLoading, + toMiddlewareChain, + getUpdatedBridgeRequirementsParams, + ], + ); +}; diff --git a/frontend/components/errors/ErrorComponent.tsx b/frontend/components/errors/ErrorComponent.tsx deleted file mode 100644 index 12765eb20..000000000 --- a/frontend/components/errors/ErrorComponent.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export const ErrorComponent = () => { - return Error; -}; diff --git a/frontend/components/styled/CardFlex.tsx b/frontend/components/styled/CardFlex.tsx index 25030cc36..6e7d945f7 100644 --- a/frontend/components/styled/CardFlex.tsx +++ b/frontend/components/styled/CardFlex.tsx @@ -2,24 +2,46 @@ import { Card } from 'antd'; import styled from 'styled-components'; type CardFlexProps = { + /** @deprecated Use $gap instead */ gap?: number; + /** @deprecated Use $noBodyPadding instead */ noBodyPadding?: 'true' | 'false'; + /** @deprecated Use $noBorder instead */ noBorder?: boolean; + $gap?: number; + $noBodyPadding?: boolean; + $noBorder?: boolean; + $padding?: string; }; + export const CardFlex = styled(Card).withConfig({ shouldForwardProp: (prop: string) => !['gap', 'noBodyPadding', 'noBorder'].includes(prop), })` - ${(props) => !!props.noBorder && 'border: none;'} + ${(props) => !!(props.noBorder || props.$noBorder) && 'border: none;'} .ant-card-body { ${(props) => { - const { gap, noBodyPadding } = props; + const { + gap: legacyGap, + $gap, + noBodyPadding: legacyNoBodyPadding, + $noBodyPadding, + } = props; + const gap = legacyGap || $gap; + const noBodyPadding = legacyNoBodyPadding === 'true' || $noBodyPadding; + const gapStyle = gap ? `gap: ${gap}px;` : ''; - const paddingStyle = noBodyPadding === 'true' ? 'padding: 0;' : ''; - return `${gapStyle} ${paddingStyle}`; + const paddingStyle = noBodyPadding + ? 'padding: 0;' + : (props.$padding && `padding: ${props.$padding};`) || ''; + + return ` + display: flex; + flex-direction: column; + ${gapStyle} + ${paddingStyle} + `; }} - display: flex; - flex-direction: column; } `; diff --git a/frontend/components/styled/CardSection.tsx b/frontend/components/styled/CardSection.tsx index 5e28ceb45..4de7dbe10 100644 --- a/frontend/components/styled/CardSection.tsx +++ b/frontend/components/styled/CardSection.tsx @@ -4,10 +4,15 @@ import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; type CardSectionProps = FlexProps & { + /** @deprecated Use $borderTop instead */ bordertop?: 'true' | 'false'; + /** @deprecated Use $borderBottom instead */ borderbottom?: 'true' | 'false'; + /** @deprecated Use $padding instead */ padding?: string; - vertical?: boolean; + $borderTop?: boolean; + $borderBottom?: boolean; + $padding?: string; }; /** @@ -17,19 +22,26 @@ type CardSectionProps = FlexProps & { */ export const CardSection = styled(Flex)` ${(props) => { - const { padding, borderbottom, bordertop } = props; + const { + padding, + borderbottom, + bordertop, + vertical, + $borderBottom, + $borderTop, + $padding, + } = props; - const paddingStyle = `padding: ${padding ?? '0px'};`; + const paddingStyle = `padding: ${(padding || $padding) ?? '0px'};`; const borderTopStyle = - bordertop === 'true' + bordertop === 'true' || $borderTop ? `border-top: 1px solid ${COLOR.BORDER_GRAY};` : 'border-top: none;'; const borderBottomStyle = - borderbottom === 'true' + borderbottom === 'true' || $borderBottom ? `border-bottom: 1px solid ${COLOR.BORDER_GRAY};` : 'border-bottom: none;'; - - const verticalStyle = props.vertical ? 'flex-direction: column;' : ''; + const verticalStyle = vertical ? 'flex-direction: column;' : ''; return ` ${paddingStyle} diff --git a/frontend/components/ui/iconStyles.ts b/frontend/components/ui/iconStyles.ts new file mode 100644 index 000000000..e14176106 --- /dev/null +++ b/frontend/components/ui/iconStyles.ts @@ -0,0 +1,6 @@ +import { COLOR } from '@/constants/colors'; + +export const LIGHT_ICON_STYLE = { color: COLOR.TEXT_LIGHT }; +export const WARNING_ICON_STYLE = { color: COLOR.WARNING }; +export const SUCCESS_ICON_STYLE = { color: COLOR.SUCCESS }; +export const ERROR_ICON_STYLE = { color: COLOR.RED }; diff --git a/frontend/config/agents.ts b/frontend/config/agents.ts index e66bdb742..47abb3ec7 100644 --- a/frontend/config/agents.ts +++ b/frontend/config/agents.ts @@ -12,6 +12,7 @@ import { AgentsFunBaseService } from '@/service/agents/AgentsFunBase'; import { ModiusService } from '@/service/agents/Modius'; import { OptimismService } from '@/service/agents/Optimism'; import { PredictTraderService } from '@/service/agents/PredictTrader'; +import { Address } from '@/types/Address'; import { AgentConfig } from '@/types/Agent'; import { MODE_TOKEN_CONFIG, OPTIMISM_TOKEN_CONFIG } from './tokens'; @@ -22,7 +23,7 @@ const getModiusUsdcConfig = () => { ?.fund_requirements; const modiusUsdcConfig = MODE_TOKEN_CONFIG[TokenSymbol.USDC]; const usdcSafeRequirement = - modiusFundRequirements?.[modiusUsdcConfig.address as string]?.safe || 0; + modiusFundRequirements?.[modiusUsdcConfig.address as Address]?.safe || 0; return Number(formatUnits(usdcSafeRequirement, modiusUsdcConfig.decimals)); }; @@ -32,7 +33,7 @@ const getOptimusUsdcConfig = () => { ?.fund_requirements; const optimusUsdcConfig = OPTIMISM_TOKEN_CONFIG[TokenSymbol.USDC]; const usdcSafeRequirement = - optimusFundRequirements?.[optimusUsdcConfig.address as string]?.safe || 0; + optimusFundRequirements?.[optimusUsdcConfig.address as Address]?.safe || 0; return Number(formatUnits(usdcSafeRequirement, optimusUsdcConfig.decimals)); }; diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index b1277594a..ecf8a40e5 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -42,6 +42,26 @@ export type ChainTokenConfig = { [tokenSymbol: string]: TokenConfig; }; +export const ETHEREUM_TOKEN_CONFIG: ChainTokenConfig = { + [TokenSymbol.ETH]: { + tokenType: TokenType.NativeGas, + decimals: 18, + symbol: TokenSymbol.ETH, + }, + [TokenSymbol.OLAS]: { + address: '0x0001A500A6B18995B03f44bb040A5fFc28E45CB0', + decimals: 18, + tokenType: TokenType.Erc20, + symbol: TokenSymbol.OLAS, + }, + [TokenSymbol.USDC]: { + address: '0xA0b86991c6218b36c1d19D4a2e9EB0CE3606EB48', + decimals: 6, + tokenType: TokenType.Erc20, + symbol: TokenSymbol.USDC, + }, +} as const; + const GNOSIS_TOKEN_CONFIG: ChainTokenConfig = { [TokenSymbol.XDAI]: { decimals: 18, @@ -140,6 +160,11 @@ export const OPTIMISM_TOKEN_CONFIG: ChainTokenConfig = { }, }; +/** + * TODO: + * 1. combine EvmChainId and AllEvmChainId into one thing to avoid confusion + * 2. include ethereum config into this and make it so balances are not requested for it + */ export const TOKEN_CONFIG: Record = { [EvmChainId.Gnosis]: GNOSIS_TOKEN_CONFIG, [EvmChainId.Base]: BASE_TOKEN_CONFIG, diff --git a/frontend/constants/address.ts b/frontend/constants/address.ts index 4b918c97b..b96c0445b 100644 --- a/frontend/constants/address.ts +++ b/frontend/constants/address.ts @@ -1,3 +1,8 @@ import { ethers } from 'ethers'; +import { Address } from '@/types/Address'; + export const AddressZero = ethers.constants.AddressZero; + +export const ETHEREUM_OLAS_ADDRESS: Address = + '0x0001A500A6B18995B03f44bb040A5fFc28E45CB0'; diff --git a/frontend/constants/colors.ts b/frontend/constants/colors.ts index 1cf8b942f..7c7d0f1b4 100644 --- a/frontend/constants/colors.ts +++ b/frontend/constants/colors.ts @@ -15,4 +15,6 @@ export const COLOR = { NEUTRAL_4: '#A3AEBB', GRAY_1: '#f2f4f9', GRAY_2: '#4D596A', + SUCCESS: '#52C41A', + WARNING: '#FA8C16', }; diff --git a/frontend/constants/intervals.ts b/frontend/constants/intervals.ts index 4c29ead69..242c0f870 100644 --- a/frontend/constants/intervals.ts +++ b/frontend/constants/intervals.ts @@ -2,6 +2,8 @@ export const ONE_SECOND_INTERVAL = 1_000; export const FIVE_SECONDS_INTERVAL = 5 * ONE_SECOND_INTERVAL; +export const TEN_SECONDS_INTERVAL = 10 * ONE_SECOND_INTERVAL; + export const FIFTEEN_SECONDS_INTERVAL = 15 * ONE_SECOND_INTERVAL; export const ONE_MINUTE_INTERVAL = 60 * ONE_SECOND_INTERVAL; diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index a0f1fa277..4fa3a67a3 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -1,4 +1,5 @@ import { Safe } from '@/enums/Wallet'; +import { BridgeRefillRequirementsRequest } from '@/types/Bridge'; import { Maybe } from '@/types/Util'; export const REACT_QUERY_KEYS = { @@ -77,4 +78,11 @@ export const REACT_QUERY_KEYS = { // balances and funding requirements BALANCES_AND_REFILL_REQUIREMENTS_KEY: (serviceConfigId: string) => ['balancesAndRefillRequirements', serviceConfigId] as const, + + // bridge + BRIDGE_REFILL_REQUIREMENTS_KEY: (params: BridgeRefillRequirementsRequest) => + ['bridgeRefillRequirements', params] as const, + BRIDGE_STATUS_BY_QUOTE_ID_KEY: (quoteId: string) => + ['bridgeStatusByQuoteId', quoteId] as const, + BRIDGE_EXECUTE_KEY: (quoteId: string) => ['bridgeExecute', quoteId] as const, } as const; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index a9c951601..bf9a907c2 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -9,12 +9,12 @@ import { parseEther, parseUnits } from '@/utils/numberFormatters'; export const PREDICT_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.PredictTrader, // TODO: remove if causes errors on middleware - name: 'Trader Agent', // Should be unique across all services and not be updated - hash: 'bafybeihgmbbjtkrlu62bkm3e4j2ehqipv5huqpifjiyttvjrk4sikwsfzu', + name: 'Trader Agent', // should be unique across all services and not be updated + hash: 'bafybeihe7r2a2vnbbqrzczlzjhhmzypxbre3gobupc65w4ea266hmk5efu', description: 'Trader agent for omen prediction markets', image: 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', - service_version: 'v0.25.0', + service_version: 'v0.25.5', home_chain: MiddlewareChain.GNOSIS, configurations: { [MiddlewareChain.GNOSIS]: { @@ -83,7 +83,13 @@ export const PREDICT_SERVICE_TEMPLATE: ServiceTemplate = { name: 'Tools accuracy hash', description: '', // Use the latest value from https://github.com/valory-xyz/quickstart/blob/main/configs/config_predict_trader.json#L74 - value: 'QmVCKTpXjK6gtcsCBivrGVaH1rQuBgtEVVMTjmn3uE1mZp', + value: 'QmTzMoaEtSRdAnVxpziXVNwqYcE6HVZpGs6TM8vhWw1HPt', + provision_type: EnvProvisionType.FIXED, + }, + MECH_INTERACT_ROUND_TIMEOUT_SECONDS: { + name: 'Mech interact round timeout', + description: '', + value: '900', // 15 min provision_type: EnvProvisionType.FIXED, }, }, @@ -93,11 +99,11 @@ const AGENTS_FUN_COMMON_TEMPLATE: Pick< ServiceTemplate, 'env_variables' | 'hash' | 'image' | 'description' | 'service_version' > = { - hash: 'bafybeidxfdlaeywhnhafix2yzrnbldk5cybwal53o6mtabnamnxmwtprea', + hash: 'bafybeiajnpysvflxlbsynl4ybsdhgbbrx5hdjvzzdsxnbb6ejia4mrdmdi', image: 'https://gateway.autonolas.tech/ipfs/QmQYDGMg8m91QQkTWSSmANs5tZwKrmvUCawXZfXVVWQPcu', description: 'Memeooorr @twitter_handle', // should be overwritten with twitter username - service_version: 'v0.4.2-alpha1', + service_version: 'v0.5.0-alpha3', env_variables: { BASE_LEDGER_RPC: { name: 'Base ledger RPC', @@ -111,26 +117,32 @@ const AGENTS_FUN_COMMON_TEMPLATE: Pick< value: '', provision_type: EnvProvisionType.COMPUTED, }, - TWIKIT_USERNAME: { - name: 'Twitter username', + TWEEPY_CONSUMER_API_KEY: { + name: 'Twitter consumer API key', + description: '', + value: '', + provision_type: EnvProvisionType.USER, + }, + TWEEPY_CONSUMER_API_KEY_SECRET: { + name: 'Twitter consumer API key secret', description: '', value: '', provision_type: EnvProvisionType.USER, }, - TWIKIT_EMAIL: { - name: 'Twitter email', + TWEEPY_BEARER_TOKEN: { + name: 'Twitter bearer token', description: '', value: '', provision_type: EnvProvisionType.USER, }, - TWIKIT_PASSWORD: { - name: 'Twitter password', + TWEEPY_ACCESS_TOKEN: { + name: 'Twitter access token', description: '', value: '', provision_type: EnvProvisionType.USER, }, - TWIKIT_COOKIES: { - name: 'Twitter cookies', + TWEEPY_ACCESS_TOKEN_SECRET: { + name: 'Twitter access token secret', description: '', value: '', provision_type: EnvProvisionType.USER, @@ -253,7 +265,7 @@ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = { export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Modius, name: 'Optimus', // Should be unique across all services and not be updated - hash: 'bafybeiecjxha2ouqupttgdax7j4xmzfr6icuu55kq5xo2bwhkrl2po5khq', + hash: 'bafybeicxflz5lzklgc522zytvwi4rgycghdqdmzgkxojnjatommr7qvqfm', description: 'Optimus', image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', diff --git a/frontend/constants/urls.ts b/frontend/constants/urls.ts index 4499829b1..13df353cf 100644 --- a/frontend/constants/urls.ts +++ b/frontend/constants/urls.ts @@ -19,10 +19,10 @@ const SWAP_OPTIMISM_URL: Url = 'https://balancer.fi/pools/optimism/v2/0x5bb3e58887264b667f915130fd04bbb56116c27800020000000000000000012a'; // olas.network -export const OPERATE_URL: Url = 'https://olas.network/operate'; -export const FAQ_URL: Url = 'https://olas.network/operate#faq'; +export const PEARL_URL: Url = 'https://olas.network/pearl'; +export const FAQ_URL: Url = 'https://olas.network/pearl#faq'; export const TERMS_AND_CONDITIONS_URL: Url = 'https://olas.network/pearl-terms'; -export const DOWNLOAD_URL: Url = 'https://olas.network/operate#download'; +export const DOWNLOAD_URL: Url = 'https://olas.network/pearl#download'; // thegraph export const REWARDS_HISTORY_SUBGRAPH_URLS_BY_EVM_CHAIN: Record< diff --git a/frontend/context/BalancesAndRefillRequirementsProvider.tsx b/frontend/context/BalancesAndRefillRequirementsProvider.tsx index e3be422a6..407ef741a 100644 --- a/frontend/context/BalancesAndRefillRequirementsProvider.tsx +++ b/frontend/context/BalancesAndRefillRequirementsProvider.tsx @@ -1,7 +1,11 @@ -import { useQuery } from '@tanstack/react-query'; +import { QueryObserverResult, useQuery } from '@tanstack/react-query'; import { createContext, PropsWithChildren, useMemo } from 'react'; -import { AddressBalanceRecord, BalancesAndFundingRequirements } from '@/client'; +import { + AddressBalanceRecord, + BalancesAndFundingRequirements, + MasterSafeBalanceRecord, +} from '@/client'; import { FIVE_SECONDS_INTERVAL, ONE_MINUTE_INTERVAL, @@ -12,19 +16,27 @@ import { usePageState } from '@/hooks/usePageState'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { BalanceService } from '@/service/balances'; -import { Optional } from '@/types/Util'; +import { Nullable, Optional } from '@/types/Util'; import { asMiddlewareChain } from '@/utils/middlewareHelpers'; export const BalancesAndRefillRequirementsProviderContext = createContext<{ isBalancesAndFundingRequirementsLoading: boolean; balances: Optional; - refillRequirements: Optional; + refillRequirements: Optional; + totalRequirements: Optional; canStartAgent: boolean; + isRefillRequired: boolean; + refetch: Nullable< + () => Promise> + >; }>({ isBalancesAndFundingRequirementsLoading: false, balances: undefined, refillRequirements: undefined, + totalRequirements: undefined, canStartAgent: false, + isRefillRequired: false, + refetch: null, }); export const BalancesAndRefillRequirementsProvider = ({ @@ -50,6 +62,7 @@ export const BalancesAndRefillRequirementsProvider = ({ const { data: balancesAndRefillRequirements, isLoading: isBalancesAndFundingRequirementsLoading, + refetch, } = useQuery({ queryKey: REACT_QUERY_KEYS.BALANCES_AND_REFILL_REQUIREMENTS_KEY( configId as string, @@ -69,9 +82,9 @@ export const BalancesAndRefillRequirementsProvider = ({ return balancesAndRefillRequirements.balances[asMiddlewareChain(chainId)]; }, [ - balancesAndRefillRequirements, - chainId, isBalancesAndFundingRequirementsLoading, + chainId, + balancesAndRefillRequirements, ]); const refillRequirements = useMemo(() => { @@ -82,9 +95,22 @@ export const BalancesAndRefillRequirementsProvider = ({ asMiddlewareChain(chainId) ]; }, [ - balancesAndRefillRequirements, + isBalancesAndFundingRequirementsLoading, chainId, + balancesAndRefillRequirements, + ]); + + const totalRequirements = useMemo(() => { + if (isBalancesAndFundingRequirementsLoading) return; + if (!balancesAndRefillRequirements) return; + + return balancesAndRefillRequirements.total_requirements[ + asMiddlewareChain(chainId) + ]; + }, [ isBalancesAndFundingRequirementsLoading, + chainId, + balancesAndRefillRequirements, ]); return ( @@ -93,8 +119,12 @@ export const BalancesAndRefillRequirementsProvider = ({ isBalancesAndFundingRequirementsLoading, refillRequirements, balances, + totalRequirements, canStartAgent: balancesAndRefillRequirements?.allow_start_agent || false, + isRefillRequired: + balancesAndRefillRequirements?.is_refill_required || false, + refetch: refetch || null, }} > {children} diff --git a/frontend/context/ElectronApiProvider.tsx b/frontend/context/ElectronApiProvider.tsx index b8ef56589..8f29d7694 100644 --- a/frontend/context/ElectronApiProvider.tsx +++ b/frontend/context/ElectronApiProvider.tsx @@ -2,7 +2,6 @@ import { get } from 'lodash'; import { createContext, PropsWithChildren } from 'react'; import { AgentHealthCheckResponse } from '@/types/Agent'; -import { XCookie } from '@/types/Cookies'; import { ElectronStore, ElectronTrayIconStatus } from '@/types/ElectronApi'; type ElectronApiAgentActivityWindow = { @@ -43,15 +42,6 @@ type ElectronApiContextProps = { debugData?: Record; }) => Promise<{ success: true; dirPath: string } | { success?: false }>; openPath?: (filePath: string) => void; - validateTwitterLogin?: ({ - username, - password, - email, - }: { - username: string; - password: string; - email: string; - }) => Promise<{ success: boolean; cookies?: XCookie[] }>; healthCheck?: () => Promise< { response: AgentHealthCheckResponse | null } | { error: string } >; @@ -79,7 +69,6 @@ export const ElectronApiContext = createContext({ setAppHeight: () => {}, saveLogs: async () => ({ success: false }), openPath: () => {}, - validateTwitterLogin: async () => ({ success: false }), healthCheck: async () => ({ response: null }), agentActivityWindow: { init: async () => {}, @@ -129,7 +118,6 @@ export const ElectronApiProvider = ({ children }: PropsWithChildren) => { showNotification: getElectronApiFunction('showNotification'), saveLogs: getElectronApiFunction('saveLogs'), openPath: getElectronApiFunction('openPath'), - validateTwitterLogin: getElectronApiFunction('validateTwitterLogin'), healthCheck: getElectronApiFunction('healthCheck'), agentActivityWindow: { init: getElectronApiFunction('agentActivityWindow.init'), diff --git a/frontend/context/MasterWalletProvider.tsx b/frontend/context/MasterWalletProvider.tsx index 342ea8b34..ba9796550 100644 --- a/frontend/context/MasterWalletProvider.tsx +++ b/frontend/context/MasterWalletProvider.tsx @@ -1,6 +1,12 @@ import { QueryObserverBaseResult, useQuery } from '@tanstack/react-query'; import { getAddress, isAddress } from 'ethers/lib/utils'; -import { createContext, PropsWithChildren, useContext, useState } from 'react'; +import { + createContext, + PropsWithChildren, + useContext, + useMemo, + useState, +} from 'react'; import { MiddlewareWalletResponse } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; @@ -80,15 +86,24 @@ export const MasterWalletProvider = ({ children }: PropsWithChildren) => { ), }); - const masterEoa = masterWallets?.find( - (wallet): wallet is MasterEoa => - wallet.type === WalletType.EOA && wallet.owner === WalletOwnerType.Master, + const masterEoa = useMemo( + () => + masterWallets?.find( + (wallet): wallet is MasterEoa => + wallet.type === WalletType.EOA && + wallet.owner === WalletOwnerType.Master, + ), + [masterWallets], ); - const masterSafes = masterWallets?.filter( - (wallet): wallet is MasterSafe => - wallet.type === WalletType.Safe && - wallet.owner === WalletOwnerType.Master, + const masterSafes = useMemo( + () => + masterWallets?.filter( + (wallet): wallet is MasterSafe => + wallet.type === WalletType.Safe && + wallet.owner === WalletOwnerType.Master, + ), + [masterWallets], ); return ( diff --git a/frontend/context/SharedProvider/SharedProvider.tsx b/frontend/context/SharedProvider/SharedProvider.tsx index 4e7c0851d..f612389cb 100644 --- a/frontend/context/SharedProvider/SharedProvider.tsx +++ b/frontend/context/SharedProvider/SharedProvider.tsx @@ -2,10 +2,13 @@ import { createContext, PropsWithChildren, useCallback, + useEffect, useRef, useState, } from 'react'; +import { AgentType } from '@/enums/Agent'; +import { useServices } from '@/hooks/useServices'; import { Optional } from '@/types/Util'; import { useMainOlasBalance } from './useMainOlasBalance'; @@ -21,9 +24,8 @@ export const SharedContext = createContext<{ onboardingStep: number; updateOnboardingStep: (step: number) => void; - // healthcheck alert shown to user - isHealthCheckAlertShown: boolean; - setHealthCheckAlertShown: (e: boolean) => void; + // agent specific checks + isMemeooorrFieldUpdateCompleted: boolean; // others }>({ @@ -36,9 +38,8 @@ export const SharedContext = createContext<{ onboardingStep: 0, updateOnboardingStep: () => {}, - // healthcheck alert shown to user - isHealthCheckAlertShown: false, - setHealthCheckAlertShown: () => {}, + // agent specific checks + isMemeooorrFieldUpdateCompleted: false, // others }); @@ -64,12 +65,28 @@ export const SharedProvider = ({ children }: PropsWithChildren) => { hasAnimatedRef.current = value; }, []); - // state to show healthcheck alert to the user - const [isHealthCheckAlertShown, setHealthCheckErrorsShownToUser] = - useState(false); - const setHealthCheckAlertShown = useCallback((isShown: boolean) => { - setHealthCheckErrorsShownToUser(isShown); - }, []); + // agent specific checks + const { selectedAgentType, selectedService } = useServices(); + const [isMemeooorrFieldUpdateCompleted, setIsMemeooorrFieldUpdateCompleted] = + useState(true); // default to true to avoid showing the alert on first load + + // Users with the Memeooorr agent type are required to update their + // agent configurations to run the latest version of the agent. + useEffect(() => { + if (!selectedAgentType) return; + if (selectedAgentType !== AgentType.Memeooorr) return; + if (!selectedService) return; + + const areFieldsUpdated = [ + 'TWEEPY_CONSUMER_API_KEY', + 'TWEEPY_CONSUMER_API_KEY_SECRET', + 'TWEEPY_BEARER_TOKEN', + 'TWEEPY_ACCESS_TOKEN', + 'TWEEPY_ACCESS_TOKEN_SECRET', + ].every((key) => selectedService.env_variables?.[key]?.value); + + setIsMemeooorrFieldUpdateCompleted(areFieldsUpdated); + }, [selectedAgentType, selectedService]); return ( { onboardingStep, updateOnboardingStep, - // healthcheck errors - isHealthCheckAlertShown, - setHealthCheckAlertShown, + // agent specific checks + isMemeooorrFieldUpdateCompleted, }} > {children} diff --git a/frontend/enums/Pages.ts b/frontend/enums/Pages.ts index 721495b36..8850f5fe0 100644 --- a/frontend/enums/Pages.ts +++ b/frontend/enums/Pages.ts @@ -12,4 +12,5 @@ export enum Pages { SwitchAgent, AgentActivity, UpdateAgentTemplate, + AddFundsThroughBridge, } diff --git a/frontend/enums/SetupScreen.ts b/frontend/enums/SetupScreen.ts index 45a29595a..eed9453f5 100644 --- a/frontend/enums/SetupScreen.ts +++ b/frontend/enums/SetupScreen.ts @@ -15,4 +15,7 @@ export enum SetupScreen { RestoreViaBackup, AgentIntroduction, EarlyAccessOnly, + + /** Onboarding using the bridge */ + SetupBridgeOnboardingScreen, } diff --git a/frontend/hooks/useBackupSigner.ts b/frontend/hooks/useBackupSigner.ts new file mode 100644 index 000000000..e6d3f5b63 --- /dev/null +++ b/frontend/hooks/useBackupSigner.ts @@ -0,0 +1,15 @@ +import { useMultisigs } from './useMultisig'; +import { useSetup } from './useSetup'; +import { useMasterWalletContext } from './useWallet'; + +/** + * Hook to get the backup signer address. + */ +export const useBackupSigner = () => { + const { backupSigner } = useSetup(); + const { masterSafes } = useMasterWalletContext(); + const { allBackupAddresses } = useMultisigs(masterSafes); + + const backupSignerAddress = backupSigner ?? allBackupAddresses[0]; + return backupSignerAddress; +}; diff --git a/frontend/hooks/useBridgeRefillRequirements.ts b/frontend/hooks/useBridgeRefillRequirements.ts new file mode 100644 index 000000000..559cbb8fd --- /dev/null +++ b/frontend/hooks/useBridgeRefillRequirements.ts @@ -0,0 +1,37 @@ +import { useQuery } from '@tanstack/react-query'; +import { useContext } from 'react'; + +import { TEN_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { OnlineStatusContext } from '@/context/OnlineStatusProvider'; +import { BridgeService } from '@/service/Bridge'; +import { BridgeRefillRequirementsRequest } from '@/types/Bridge'; + +export const useBridgeRefillRequirements = ( + params: BridgeRefillRequirementsRequest | null, + canPoll: boolean = true, + onSuccess?: () => void, +) => { + const { isOnline } = useContext(OnlineStatusContext); + + return useQuery({ + queryKey: REACT_QUERY_KEYS.BRIDGE_REFILL_REQUIREMENTS_KEY(params!), + queryFn: async ({ signal }) => { + const response = await BridgeService.getBridgeRefillRequirements( + params!, + signal, + ); + + if (onSuccess) onSuccess(); + return response; + }, + + refetchInterval: canPoll ? TEN_SECONDS_INTERVAL : false, + refetchOnWindowFocus: false, + enabled: isOnline && !!params, + staleTime: 0, + refetchOnMount: 'always', + refetchOnReconnect: 'always', + refetchIntervalInBackground: true, + }); +}; diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index ee51375da..f60ece00d 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -15,6 +15,8 @@ const FeatureFlagsSchema = z.enum([ 'agent-activity', 'backup-via-safe', 'agent-settings', + 'bridge-onboarding', + 'bridge-add-funds', ]); type FeatureFlags = z.infer; @@ -39,6 +41,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': true, 'agent-settings': false, + 'bridge-onboarding': false, + 'bridge-add-funds': false, }, [AgentType.Memeooorr]: { 'manage-wallet': true, @@ -50,6 +54,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': true, 'agent-settings': true, + 'bridge-onboarding': true, + 'bridge-add-funds': false, }, [AgentType.AgentsFunCelo]: { 'manage-wallet': true, @@ -61,6 +67,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': true, 'agent-settings': false, + 'bridge-onboarding': false, + 'bridge-add-funds': false, }, [AgentType.Modius]: { 'manage-wallet': true, @@ -72,6 +80,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': false, // temporarily hidden until mode is available on safe https://app.safe.global/new-safe/create 'agent-settings': true, + 'bridge-onboarding': true, + 'bridge-add-funds': false, }, [AgentType.Optimus]: { 'manage-wallet': true, diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index 035d05c8c..29d26e224 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -106,18 +106,20 @@ export const useLogs = () => { const { isLoaded: isAddressesLoaded, data: addresses } = useAddressesLogs(); const logs = useMemo(() => { - if (isServicesLoaded && isBalancesLoaded && isAddressesLoaded) { - return { - store: storeState, - debugData: { services, addresses, balances }, - }; - } + return { + store: storeState, + debugData: { + services: isServicesLoaded ? services : null, + addresses: isAddressesLoaded ? addresses : null, + balances: isBalancesLoaded ? balances : null, + }, + }; }, [ - addresses, - balances, isAddressesLoaded, isBalancesLoaded, isServicesLoaded, + addresses, + balances, services, storeState, ]); diff --git a/frontend/hooks/usePageState.ts b/frontend/hooks/usePageState.ts index daad4b3aa..008f38348 100644 --- a/frontend/hooks/usePageState.ts +++ b/frontend/hooks/usePageState.ts @@ -1,4 +1,4 @@ -import { useContext } from 'react'; +import { useCallback, useContext } from 'react'; import { PageStateContext } from '@/context/PageStateProvider'; import { Pages } from '@/enums/Pages'; @@ -6,9 +6,12 @@ import { Pages } from '@/enums/Pages'; export const usePageState = () => { const pageState = useContext(PageStateContext); - const goto = (state: Pages) => { - pageState.setPageState(state); - }; + const goto = useCallback( + (state: Pages) => { + pageState.setPageState(state); + }, + [pageState], + ); return { goto, ...pageState }; }; diff --git a/frontend/pages/index.tsx b/frontend/pages/index.tsx index 7547c6b0e..0aaf42c8d 100644 --- a/frontend/pages/index.tsx +++ b/frontend/pages/index.tsx @@ -2,6 +2,7 @@ import { useEffect, useMemo } from 'react'; import { AgentActivityPage } from '@/components/AgentActivity'; import { AgentSelection } from '@/components/AgentSelection'; +import { AddFundsThroughBridge } from '@/components/bridge/AddFundsThroughBridge'; import { Main } from '@/components/MainPage'; import { ManageStakingPage } from '@/components/ManageStakingPage'; import { AddBackupWalletViaSafePage } from '@/components/Pages/AddBackupWalletViaSafePage'; @@ -67,6 +68,11 @@ export default function Home() { return ; case Pages.UpdateAgentTemplate: return ; + + // bridge pages + case Pages.AddFundsThroughBridge: + return ; + default: return
      ; } diff --git a/frontend/public/chains/base-chain.png b/frontend/public/chains/base-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..38b747114cb007e83cd4e652f5ab7ab2e0ad6596 GIT binary patch literal 2894 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 literal 0 HcmV?d00001 diff --git a/frontend/public/chains/ethereum-chain.png b/frontend/public/chains/ethereum-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..f9685c478d193338893ec9837b3d39b83c00bca5 GIT binary patch literal 2769 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 AYXATM literal 0 HcmV?d00001 diff --git a/frontend/public/olas-icon.png b/frontend/public/olas-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..87e8ff76b6d5d199ebeb0191443d07b8f2401bf6 GIT binary patch literal 35622 zcmeIbYg|*;x;{DpuNB2ETSZY&+pVodi8oM0u#0LhB536*08;Q4kwoZmkCzqj)P#(5j# zy}!>p=6vU&wXPqJePhZSgpjeHe)7@hgp9(^QDoEz{F9qeDQssjEtzw*>VBaHHTd(DB@9Qc310p@*Q_owm& z`ZL+quKl_yWt~#zpoyNW-zi+=D)DGg=#F;ldTR~0+%Na&{j2S&E?}jnES^417Yossl)YW3EiwE zZ3)|V>S{{kSL*kXRT8U#0MGKR8!P(Obhp(87^ZH1xOUr*;bU71<;rI{hMlIKi9Ihg z<|AG@dk>F)_NFEG2@<~__Xhmp6wQ0Z#2 zBnDBk6L$yiSI#%RJJ)bO)@rI}@8r7ad!IL5&ofN(%6BUp`nv)rpX>X3!dN0C^=$a74xZm{8e4qr9rl{?_%nY=bPql8Jv() ztE4|+`*&GkZ9{CYw}{X0eRO?6{=KT+A)Q$zHSm2~Xm*u;GJ-i7!5!?;P48v37kt+L zR4-n}sIBJVUaN}f8%jcd?5Q@WqDgMT)$+3J$Y9-o{&JZ!X5J)*!rYqTKg1^CZ16lM zG1MbPZz@byYt4vDf#&aRKb1AeOkp6@vSrG<+aJ8bcAKrx_Ko`k+r5Tvr;v7YR+_Ng zJ5$qcu-(}2!Sed+g17GFZ}?f$Ihvmm8?-yPBm3y4@tMJeAn0v=FC)&w)GP0o$L z(TK}6g}be)4T==A`THJ6+_Ru&mj0e0w;eD8nU6-H`>8nVh;gmRJH=_Q_Hy5HJqO_-C-0{M=vrL5y1!R{qA+8kd`sox zoj)F^FX2>P@xe_h#O5cN#nK}tvC<0Vxo8i~Tl@`}xve!1ZLBITYzs~pqA%nVFKW5& z!M_d3fgQ8qT&bJmfqfV9kLqpLG0+lsQD2EuiPtrGery!+hs<8wH?XTa2D=r_-gF4X zE?23Qv_(0c9lu*1DG%%(kDXC}&cR<*ke}$Ut`7to+mvg%sb_NG-GsJjL3_%}d2G@H zcdy_vR5&hot?~Ce>l)XAoG;X7fxA!kbcB_&d8XKVY!S7%^>t?2Flh@3jPy=9*VLz8 zk9|pRx#2Hy@tTzJ^`^9}+SK7iR3(lH=`DrP#rf-Xe$4w(=lwJ0Qr956z7+?Ab0!AQ z)^-G{&DPgAjgft8K`poEA(h$l5(A;>l7L}L1}UxoU?Pr^p2pzrK+(o&!%jDmKmEFs zdgwJI=CKF<)_?3Ln(U=9Nh{2L=ov|e>7o>o=ZRYymNom4)Q7}*V`sv*v+V$br# z#&X0G+m18QDFsvlEOQeo%6ijbny;&@>Ql8ojK_l|*eQtO2H9;;P??2hCi_?I(==%_ z^oTvpiPgNIR(V}nWIu|1A);b!pw|%7U!?de_=qRAqQF4xQ;t~ED#*2c9%%_*@Aos$ z@^|v+`NQIs#T%}vtjyCWt=(f>D6O&y^p>*i8V_CJeD%o64w?O@C89qw=uVGR{3Z1% z^IWTp`?sg`ShH*B|KAuxcQ@AkoYL1}EYn#^>Ui}DxlP9p!SKK6_L}PUJ!?%H?tSer zWtfE>)t=;n^Yd!5uR6ZLF6xdaPuZ2nE{nBAJ<>EwA`{vm0V98=D3--CU` z|5r+?Y&1`5?5*Nx-zEe(CX9-YD7MV4eR%nWF}thDpu@30``|#-Xg#fp)hX$k-n@X* z8{iO`oCS0m&60AZ&US>3G%G=@ucVJks_Yw1ux0*}GCYiIw-|_xn#d6wkiB|Yck^&& zO^iW}Rg)=CRU51FC+K?T4~(oo&Plcil&A`yU~-C%uCR3h=lq=azC|L=@QS>;+ZPw9 z%{WDN?4X`Px*yE<6MeoseL0;Qd(4Yoo3mTKWn;IQU~`)?wBaY5&i+oxB5Jp){K)hY zBA93=_h|S#y`B$m!Nr1eFusOveQXVcEPtvocu9EBdPpSNR zDyejzXJi*ANVP`le39tK2xoX3ww0r{=O#4y={%xxunUeSZ8$Zdo~l^?COx&PEv~h3 zy4Fd*9>?9xFYLjw$}9w1cdE*Y#;KmOgUbtJVejm(QB=ju^X9p3HH5J{*|e%{Z`<9%x$g)dC05lPHXp=R z#J)x9%PN!u&pK`7Ve|@fsx9no1FiL0+4dJKrIg>MoFbd9_wvg~DH_Ji*x=qUzqa$3bu*!il_xa~e?>=+W*qD(1L3J+pg|b052Ie$dYg8|8Q;KM$V8$k6 z62chF;T`Ixm|$;DD{$5qMkCx$wYmO^cJA--`P;ucYD{W(aiR3*zPY%U&2QWtgM;LL z)G3qnEGph8%Gan(IXEVp>?cZzc>E?&=W*g42L{i`&m5b~MTkm;6)9V(3vn$sy{&uLHv_i}_!UY_ z*uvI>Z)q;*wh$&UKRa8JjC~HrD4P}AVOXcsBbhb6UOAjx1`bnIOAR~GbP12S>;UE+yQ!353h{h4lMT=|92KujxClR4(Uvl)rbk0jpu!Zuh$os@%K%DT% zi6nfgdzY0&d(A~OaJh#d$KFLU7O$j^OR!Zl*HN=zg)WA(0;3gHseR4akFJJ_z zpWUXE6l0%YGL?hyWU+FA>wpPcW*|By4Eu$j9haNQIhx-9%}T!qY77-qO;M6ytj3oO zlK)j3gsZjdGz;6e(i>I(hBLVM>^046q!CGfejfVWLOEE!YzO`_8o5WEd=r=!;^*gK z2OjqPC*^y+lZGv~8i+I^>KM(M55u@i%u8`0v-hHbVpXi>7?CRdF2Mr`Hgw{$K%^Ts zl1B3Z6B3Y9zOpsn{ybH1^J#84$QE_a?&({vtAZw-5{W#T=#jD100pkRels^W=%u{h z4*LbOs+0$n)O)c{=1PysONzqb8btkBIenK@rQBaI~4$yg%e1~ z^`Gpex6&Lk^62kgzM840}O zAuYNLL*zye-ml9;tbk^Zafdw#pBLvlwQwUdqr-8Cte1Nv zhRdA@>*(thCh3LrM$-t*-nFiMc(C1=u=#s`Z0BzIoE=AuiO{SF%wqQ5Hq%z~3|3vzE^80QUCdLUQo;wW(hlh{ z<#ezo6f_1pQtmQuax@0&X(Y*cdhLCOrqj$tpY+n|1`JrxGOOK(5#cs0H9f&ZgRPRr zhzar7V_FXp3SyB;XWM6wgBFy8d+W7UD5Sh+zY_)5(NIV#a$QTtDrVvI@svjMpR$W% zX~;kDd~f$G3XFsVhRQthK9`~{KMFrgT5eMzzCjoxn&?F2aQTIN9nOp$CxtRuVZ3GB zg#DIfmF2if_G7#vQLwmjZ>A-V`E~(?$t?H`mdMKQ$&;0ParGEVi!8J%zjs{;u2^J% zVY2yo_-}*(nGiPrRJvwqQNTa^V1BkV@Yi3-Q)b&k<}P)cL_b6t1lR@dL=%{~PLmZO^POc~L$F2bOk7?YMMZwT9A}nD@!DmttxzBuBh^F zO5lxR{{^Y4di$>GLPb+?mDf1wvHWB|F=jNdZ#KR9)I8V8MuZ)20G$pOv6l^aR^zHc zsNrQAIs>Y7h~_uix|uvOfuWfeBca1NYoCA#w(9cpJEUiEZ6Kf8a8&}ABa~1*tj2AV zI0Q!1rCEP?Alyp$td$4@vZRG_KkVV0e{G&ij8#5ZEf{Xd(POA1O#kBhh{xi$DW{Wu zsLf9^>07DT0$KWY(o=b;iC@$@8*a*+h7+cghIK}B@7nv|rJ`CdQKobgNE14Vf-|(x z8xq^#+-=Vh`8|ka_T~->RMF90ZJhb|i2%2vX>0%KLDeN?F6E@Q4A=s+lL9Dq{Pb_oO+bc|paRqO1*91YNK@cf(v*bc{%|wXVTn3Sv z$FCImWub-uPg@<_P(4F4^G}qIOlcmI@S#|)qi_TXEQhR*Yu=~vluGnKR{VNf@LFX+ z*84ePlXzT><869m%^rcXXTP(q<#9DeEaULk#t}p?igFZScV>IvZ&auWt9e=zm4z@k z5uJC$5Um3LLG;B=EQM~B)bK8s$kOh~8ZzCu+)MxdZ_nx`s}Q2YO-@2Fntp6(<|^x z{RJhrtVv%p0U0@RkJ-BLq?rhc&^P(LkFb2s8B>bpm7? zl|3k1+1!j^r-R+`^;MX}r*tNfu-26#i~Z1Y#*a!jZdE@lM*GVIOe3xC+WYvIIpd>; zn_6xlWXTkML1>%J0Mr#Q-LkZE*YFMCJyO z$q0#z?sLsVgvVSA^xY{v*o0O~2H_@Ww&_yoycP+a-d;e1njO(5yxp>Ip_Fj&IVHTT zgoj|lYUr3?n!b_%(aZtb9QSmgo;k4GT93Nm+5ds7glQCTCBJ|L z{tMU0#vsbRNxdZ-*A{jqhQpe&b$Qe~(U>rYn}>_D?%fr-T|3K1m18O+FcsMzt~z)4 zsuM1)z3U{dvoYy%dPh78hiO5fK3`jPSbJATE8{D|c*GO+AuNtrgBZx^G)c?N_V)s( zqKq)ymCP*-B?oA|2_AZe*{rjU@+B!K08wg+J+OfYU4q`ucrZ$W@Dmyo2Cjj zkM#8-{0=y4K-uay0J5pSwr@X&84=Z2$Wa^C#30%I0&-MO0p+79cPT&Z;2EZw+Ln4sQ2T0V8Af5M>VI~e)<0KGW z&ku-AsBk4~xuODwYuH7+*4v$j*EnYL@~AQ`*v?l`cYz!-!;0hAYAJ|oS4(}hx22s07O%$ zu^$LTu*iV1F{_;%$_CtGk6Z?y4g{`C@j%rVKS|~9R&uA>9Uv(}Xi0>lIGRuOq{6oo zwtlLC=w**^Mt#=2>>HHkp6cRa3F>wshcQ3ugzQ7!fnFlkr?pXUVl|V*T;p=Cms@s3OF^L#15hGbm-OJs2o1 zLte|SZsqZ2Oav|@u_w-AxroAr*!lFr!e@_9+G9VHSisk>s$sFD?A9hxN&!6|*~1l{ zWR*205inR*z$I(iBpwggQKTBhZq?LR92i^BT{u6LuPcaez)}ZFd5nF~h2F9tN9Ugo znxAkqTY+Zv5Y5i{JTx0HgDR?mP=)@Zm|i5nqMV?7X^MXPo$eu)uHoF^sE<3$a5#LkErjfly* zi{yXQ=Fl5H&j8M*mRui`2Uye3?7uut$dsOGCVxV~#3vY{5b zk@&=j(L@@cHY6@7&hPk^R%h8%ibMM|^_c$ploM+RVYGp%W>v2=*%MYSR3=I^5)UD`I}&A zf`^x%qlTt$Bw1A!Jpn75g1>>tqQP1MVwI;?*5eVMkyZafi7sKKliG=|-{4*a8jeQ6 zC!NThQ#_l!X7j@f?Lec1qmczdXJ#PP;-DDE+fM7ody0Nwf{hLu2E!#rD(Nwd6-8XO>C zSxCho1ckv~kd{d~I>(?oRDa5l`Ox&5!`q6lQL+(EK!y9Hh-x2ke9Er{GGQp%Tsbuq z42fc?Yi*fZo7r7!6VeRt6g8P<96+ED=W3e87uxCGBI-9%@qb^@#S~L|#3q~J zLM`@7Fadm(U~d!jx1ekUHxI>~r_UX&j;bn|VT$-hvEj z<=i45J^%SxJzSZ9*tdSDtN?2b(&Q0okZjMn+hzSRLeVz zgf;*dNeA=`p7f|-B_)(w;f;CXK?_yf>MlK`3-&9`!ouG}Xs;{{QjO-Ns?JYV&H=X> zfMFgBmw)@niC&@VrBZ!v_SRez_WVs0!{LAn<>B-YDf^AqQDVB>jD-J0awCZI3wg>J zgG~@mtohp@wq=M|)t~xR&jeJY5^fIG6(EC~&nQwEdybr)Z-xRO7h#p}aloB{w_4M!oZ0 zhNT1N+`;4>#=UG!zhj=$?R-c0+5j+D%i;9ZM22#*AAl6*qVhu5suMz!- zMKQr1%%fwXTy#mV$yi^6BW|>6-7rG<_=(Z!S2A_D;+s(A9>0!*#O0re$PH|B1gCs# zoHqx$nL~)FEbB?39%M72j*^+tI+8kH>NlDK$UXfj{ z4x-TK?~g%<9>Sn-#p!xb7SrlM-ML?-hmPaWKn`6147BEq_PG?Ib>&5?$Z0w^7hzR4 za;s6j%^==}>Qz%czU;KNz?6noK;gma0`ACJZI55)L6QJcQGC7@0Sto8CXlzrdNbi=5Dw)HlO|GHxq%Srg1gk=RDp+;bD$J06GHC zDF`MG!B6B&Qa!CEDDqYeSuClzNQ(=Z!_7^>p0zZ(@+M0vb{{JkB^$?*-;4#;uadfn zl3L<)8>9jS0|e6tmw4m}*Yg#gx7k~#nL(C8i;*rnz15weP2>U$6Yk4Pb}ll(=bsNs zmZrM0|SY<1RD31!}7Pb*shbyYU{CA4EN9*7?f4A8ev?4<7CnPR$5ysLwPPv$pcRoXTsrX{uo)Q+W#FZjXXf%){w)z8Ncb!YgWMY1P z4|9 z!bE=gp57E0HHS>%^-kwhGoJlKmxskn<;hvk!4+QKtUJy3g_dlKgzVw|u`|sS1 z{yi#m&I)&C!LPCpRG%AtHT?XrJ4R_&W=$6aUR4H#1=Rhvuv2t;a!O1!RGCTb4ypby zu1_`gfe8ez*)X?1;{N@EVcf_}_0_*}t%70}lARxyO;waVm^x7I-*Yph`6_1wM7=S# z^!bpD@p+ZE19v+mz^Kg?tx z$QadtV_TeTmYr<3LeQg|W7EyQ{{1MVdZTt@#8NhE`DBG|$;O_q2DoYw1ech7JY`;^ zsp>|VxuV?LreAcwF`O<}V3TccyPsMy(DledJq(02`n<{p^5WrNlo&JBIuMgmasS>{ z?jrIa=V{BQMC}Dsz;6uUsmK3@jWX<4smg zZ~2;+(1q7ZL|$9ZYqtSQ_%HL9JCXP}*gt*xwDa+`c=+}D*fJ5R z$hR$S>!y$R_1vh<{M>v;Iuhf}k7odLa0{r(Gm_;jjs zbbIZB|2wA9s?AIzAX)@b9Le&O_F_e@es*15UB^fg`TJkFH;I*qi^1Ap4wJK?^dTF5 zdkvMy|2B*`ZUkXI4l4C8N0py-yj)h6T2)mwl#6-g_}_f_@+H*c`LX!;_@&F2PeY1! zU@!@Lji6pfUns}x!pnahf|}0z>etbi^5Jzs@O2RjYVh9~04ao6Fx{P{Vz;>(pt}ZsrA5k6<)A z!^7u$d3ja5$f|2wx^(Ge(o^xrAAekl)1XckWsU@%`M7l!S>otui6dL{-XsscPsY21 zRf#5ST+yM&bP2@lIvzgaxBqQPE+wDa{=Xnx`$fl*i;s(XE}4}pwZ;dxj<{*M^U3(X z2Yvp@Kg{=Ky*cXdGY`Ev>fn)g7v!!#^Y;U{oxcoP(ytZS^=?cH^!?lI72PkM`m`0^ zT{ym}KZ}2AV;bNXzcJ&?4L?_mI{#wsBrXOHo9;&Frs+1n0@dtG>TRa1p@p5(du7;a>avHaJq-uSBiWBn!HX8ncyeVc|VI!~R-btkg9TGi6{-xy_QlTSWq-Wydx@U{+ftPM@Z4B5 zA`*;|U2ya$xmd*W{N8p0wX05ytl!_5dly;`qZXOB^c?c6e##mo&WfPOkm=Baj?-WZ-^o z^p6p#f?=)yX+ea`20quE;`%<}psdtWzNcH;v+(x!dzetw<>Jf;NhyE3#xEVzR%w0Z zcoTK^^|3^@ccT1Lk^TX43)7bk!umHraA}X!%)p~oxd^X-;oK`k@i!IX`Z=AXamPlTW`pMYh!6N-WG5~sf!>PN+qq}F{KaYQRwK1^i)ih%<~Satrf=~n{j7hv zc+?7LW^8hRB#nCmmyVZOEwRseh!fR?dq~-fT_T@$_ZS|jr&d5W9lOP7u%#%6Y7|L_ zBpmgI^Ob^0>JcLdySLrT${=Bt_W@;BPXLpH=kMbVY_pqqkfTYqL#kXuZHk?S`*-s0Gg(rL zml?fHOt8PyHD)e5lRLns&6T#`LE(G9qR8|{PN1GEXZ1QPv+X1fWo^pb27~T2!jQxs zv|pL`LOa-O=%CFq?SgZDz2&CtJ9x!EwJNTAhW{9Dj1}cPg&*6EVLQzwP2LWi8s1Lx z=uWqXL=~gqz>>Z-P$=AWc%<&ByuY!UxNWm!f?uUj<}*)Hp#=^9GSsQiPXv@w>T!w3d9>bCE4=^ znW%DrE_u=3Rm>sSs4RF$WuvAzbKRd@l8lJ#!YfK^S-m#pp>_;?`zR#+OvB-8|G|yY zhUUJSzow7V?HjwmjNMw|8uPR!>g)~wZoVj_h~uj=elT%N2$DXbFO;=LKSo#ZCnYb$qu7af0czRU;Eu>#HCK3Rt)A1~+q@r-qZj<@ zKpNZa+f&?H4!;*8=iloTu7^m2^{@LKU_|26Aisk1!E^&$$pqVmUmxC$G3>4j?@ty-sIE${!_!6ev_~Gw>{E@Klc2h zQ}?%zC)!X;Quc(By7&*CRMkeXyFxjK3?Kp^#QtP|0o}N;vFj&4F7QOdQ$mW;G)m`& z>2xn)uFpTWyxR#c!<`(Ch>4!WTf#YzC5w~hHwTzKR$0;JY^?J}ucyIwlII>=O98!s zLQ8j%q6sF1TIegpM($dtai`X!xaB{L5&61zNccCC6x$Cd7va^^C;_gy-dP--Y|GoC z0xuv@3-wO+AyL+o10IxKvsb7x~Id z$vq>xa9eCA{^8LuLD$le=uDE(ZZfI3O}U``-f=4vdQcUs7q80^h&SZ;pyO3MGY$8B zpZy)fgrt`$1NFlwE}90rY0Qj-f8tHe35Rorn>Xid3FkbP!+|Xg9Y;sv9S7O`Cq}|! zhn<>xMSIS$4>}I7@YX+}&dNo8O!_4$iRhSG~-&@g(!g4{afA{>*@!S|)+dqk+ zLp0$<-_S*66NRzmiPyNat}FONPk%Eq8IzF1dr1A(mhlRQ_EkwMyZ6!ynKcEHTQ%c! zP9vGDFJLHNo`;{zuj6J%lAr$6cY*epVDIfg$5OX=rC&EECw7)OCs|<|Sgvv#a#2W| zYP0*$Gy^?O)G<_*Cw;@YDCUBdX5pFZx*TxJ~gjX|z{atXz$Dytt*MJbdc)` zUsHK7S`f1)lwj{y2o9Lb6TBVoc{?1TPI=64Jdbo6D8){ocsqJeIAp&f-H@D@v?W8r zelfA!2VGYEb8w{kdCm`xk7nOlh_`i@T1&)DT25h?!<3>PTQRfgFr`}>`fpmNQdMo0 zgWMdB+(T&UQT?>o-mT>Ot?TyUNg(+65UJ9-U8UPa6r(Y5!EoonOoq9+$np7~60U=Y z+j9`RVQ31be4thR2DT?j>g0|2A98|nLGK5NZUzycc@MjYDssSS+J_e12zcpEF(wo6 zp0`V*NaUmO=c8F_HRn4juR4(l2tg#|he5kdy_bp-nQlN z_kaggWJLyeTfZt^8OUd_(R`9hd@)qLBkdZqWMVU&c_!O0EA1Gx={>Nvj~lKXPgQ7+3N^$To_$-sSsRk7*ja65L6 zFl$i5l=lu&EIfHU*b5$$pb3O35?CZSU^*APgrD&QH{%^o?R7M4Nld7#^z$tD>ZjsY zEaihgTsj*N1(+FIVvsSDVf(Ot2}PS|1P+oFF9z|ZLji|2jTF+YK)2h_IA+@Q$F#46 z;-VgVnXq=W6^X-xA@rpZNR?Nj#r>0sdQ~TuL%S&!(I?tw^DPICx@iJvr`;F7j0J4* z9~5%)w(}3&>#+YO2C%#ikj-OM#p+5E-Ae^Lr%IRy{dzQnH&sE>{QWvBBmv|ey4NY@ zAO4^xK*CUm#R6)(+&Wp@KYd2x7wRFEy-2?wd*g$X3oSL|USo(HJ1=+&RSIBnGl5{FH?P$5|3=0b> zu0{-A-wx#>3N7*gFqk&kVpmZO>DpqzDC!93D?7#$Tk0IUg3J5H=g=!i+4JJ)W48EV zi*{=(jsk=o@5lexX5XKu4d|$K-9~U^QV)Nig@|i*a2FLc4tlQLG{Nkn6vquxT!7ca zuj(@Lo5v95))h2P3I$dvdJ`v-f@{bG&<^T0dO9xI68*9GRuj0YaK~ zVcx32Itu$_P|C-_`uYee<%|aE`(-y?A=i_Vs|qscwd~UaQB77PWI6UKI-VOar$AJP z)<9r^><@@oEd^kiO+%be;t3%+{qo3(?A(s#3u0Txl`2TMAqxlb+A#&5v}iPvXz6P` zs>OD}PVXf+Gd%occNKlIOs)H8&)#Y1;|Ge_Cg9KTcj&baKk};0KlAZcx<9clIA=Kbsgu5Z4t|oT znJ_eVSIjhLIz(Tt9)6P4UmTE#w-pu zwB<+I9VxVI=kOR4YR5Sy`BQY|p+T^Igmbs=rDL`fwhEW|(Yg?AlXm;WB(!gshr$r& z&o~oBvcBRe<#cGb0gjz^<1n@nGZ+2a*oflu5w&rnxX)#zX4a&tt;&1H;x>N+PeTeR zIN5rRf)h4KDPk$Bx>3tkIAtZ0-x0_`g|SD ztE1qEUVO2xREma*kn93pvg{-(wFlJ(EXG{F$SW_*5Z!e4ZbVM!^wC^Ok$o0NZY0R% zY?Pwl#9+G*G&Ie&+=i4rGaHwr(0I@G8LF)hGTE zY5*$EWF0a%`KD9(%Kp+rPvY=CqCH7EqEB#you=VclL?zghe=8`Kop_!05aQy7$Fl5 zSh%gS&N!jtM%VAqHNlpu{EoR4dJ@5CsFA>fr#D?suWG}(~L4+s-ykZ+{jFLMK7qBM;Q;8I=fD_~jbK9>H|w>zein~U$Zk3d;j&VF;fRUTW3d&zl<5`} zpg0Yi2Yz&I^(g(czXVwx@!e#J_Nn1bqYm|npBE#Sx=ZQ(blRrFfW&%Nu6qpZ_A*?ep4K0y#EBLiVm)<;Cq%Y zE2IktY2{D^tq0{cd>XSH_eW{t`xjFFGZh0j;xS;MFJGx+G8XZsO9F&+B6|&GGUmD- zosigT@X9+QDcUyso|Yoo3M3EDX_}V91D4Tt{yW78uiY`!?bM$_> z-o^RBSHlUrkeaPDynH?pm2w! zXp=6g$}ex^5E!AK#ZpCPOFQ#@^ElHL&KVRi(N)kJqC&4PEwFDTymOO>+4%Y#m9W}V zpPjpfQVHM1u7R;sor_8mj@`S}VlMrhs`kqA#eZJ@qnX_an$7pI*?u z{L=N8zfXbRHXv=n?x#&@iDjJuYoj*F<1Zo{`vixy;+V*zZ`b|!B3y0r$<%+D9@)Ag zXx!>E3zxoYeE9U8QSSfv=)jw6$4&cm^X5})PnO5jf4fWR zP`#mi%atnw7vCMWA+EW!ch25SL?im8kkhqewI%CyiS)Yx%ip!A(JcbVtPAT3ewo`|Jv6**0aha%pZE5C1clf`M^hUH(D(8AS-uq%1 zII-)QYXw#l^G*&&NBQ0Rb;q_jjet{-d8T3{X499FJ!pEwyj1S6SGscF#mG#7T@v%- z>CpjD8=*skatS^egfQQLXefBMs;lGovO~vqp}pu_X`0lF`&dKJQ#x<+g0sqwXINP$ z=HE8rBRZuz*oQgOjzi8p7m-fVkNpVEi?50!mAc$w&?GS5L1*z&Ka1||Ehmu5m{YwV z0>?b11Db4+do2j)aa2O)vMl@!to5{M8D>dj8w$}ZOC0|Q3X$-y2;AqQ(zOM&F4WM| z+|F1Gq`CLg9?s0Vi`YS0A`-RY-y-8l30(s(Yo3YDYR-MlK{)izpBR^&6)fqbC^jmo z!2SqrX)M_0i*aplwHT68n&v=rB-!??ef{EKgJT!^&5m{CvzPfM3$``If zwh{6H2DzIruUcX>iX^|V#hk-9o_|`8%t7GM6wC%l#p&fJFV>qjDRk!=j#3M8`Ift3 zK}pyCeLLP176MKSw#Gv@%$}83Lvbchf{FM`p5V&#tRq}AEtdx96Vb{t{XN27IE^3& z(A4;pwm%YJNm%oMPAK-qy6)aCntxY>`=)qg^wJ!0Gc=8)^->v2OCjysLpn`faK@$f zT(dZ597;b2ZBw6tr)4b6k*L=4GG;`<(w2TF?25fdCt#VL@0e)QsbfDLL-#F8D0zwG*LlFn@tiDCwH znQM@0d6kYXd*dKlbbg6e%MkE{{bG2<(caikJf8_BBK6OC;29);rn!ziM++cOMt(UP zRttfy$gmjD;o*l!P!cth>M*(Y^Mxn!5Al(#hA#g5GBV?d*v*KNJ)Y9!7aw1K$CB`RvRbDK0kN=Fy$h~HM; zx0Y&?@GvJ7(@)o@c%d*|lrIlQsU9)^9cn`C_-X0liKj=?#`-*gLQ(+A1rG7bEq(j` zy#T)opScZ0Hs>_pbW@fx@&MpECq`Cq%EQSEv6q;Scf$enFm>-#PRB?18j4b=0iYg_ zG3tMlbasuwLe03)zBX+mcA3^w8CL$hM)xpxLK4Yr2<_{zqu&vQopM7|KC{RUljC5DmVw{LsdQ(kvtYlWsWAHlItyWPHj0`A zz8!?*9-i-~3Z-A)*N8zsZ0VjwT^u{29v+K*;^S^pYqtBi5#v;{M*O(EKkg1DFEj~( zV-@c5^P2Q5%&C7qxxGvpmrb)O*@tNS3IkfX{-$(43@r4)IP4AKiM^{Q*2OtlTdcFi zd7Ocw8)CY+J|jAD+|=q8NAP)eC<=x$AOYEK}X^A1&cfFC`gdrIHdV!~=U!8#<` z?m#<%#)0 zE}@8W41M5A&EI<>-CMaOCpry$75X)FWpIWo@a9HwDGo9!?kz}Rhu_>lIxLd}&K(qRLS;OT$=*My zOjL@9Wj2Bh_u-X0x!8@55$LtKZ0iZFgfprHE)3N#;@s531w`D=k-L(TyDE$Zn-Gxu zQ{Tsn$FNp|)XLUzmMa*`g&G$hi^Bc%OkSI7bG=I4%EuFzkCU}`#q>tDT&PL<;e`+L zqBLwavuVolXW~-6OEg>A2$xIN;|t}delDM!eIdd)` zPmP$DzV1#QTn>lDd#cThKPOtjDuXh+9EUC;v^Mgh6~tDdIdLHsY7KSC=wr>;TrkSiyU-BO(x6NkP z7iYQFnCXxNaGP-K$!+U2N6*cEw&?gaeisvT_m`PWS5meFc^$Wncq}WvQ8Xf_W>*9k zPw7q}J1+3e6@8zlNzUSb?1cN2v6+=3(K^jLu67mWC0VW#jbto66^FlBB%j%0pE5V= zCuvu?CBKub$~qKewCHB`<5^VGunA43RnBD6@2u&oj>LbxFLP|_^YaRl$9EMPKObgW z6)O6?^a6FWbQ2n%-1dEVit>2b-C*lW{5~?_9%f(J8H;mTzZEc%xsZ)JlWu8_spr8I|GwHv&Y)_%f)*?)BSa6f_~q98w$+)dL{m@FXJX@-N91h;&Uu{tnSD3Y>58nJk`-GKb?`1drV@@#qE9obLHaZ7q zmF-YDIb-r(a4|RxW;UFL9ZnQ8B(py!hfMK~J{fX-TqT5Bhs1WF;eb z^P76iL7dU$=%Ifs7OaIXgSBb@R*3!E_4g*0rztbOi(MZh)^+OVK$^2I#Np%bPm*hf zX6taKLOH8t%ITw*lHq3fP5AYZFWwY-?3FwjloZwE@59H|9efx}zdgonQM1-q8#@#X zF;@U1>9(6(r_fyPFEucjjA%t-SavVN@N_K^>}*=r)0wdSz4GjPj>Z4?&WxrCfPHn5lIYH zuL@0$XbMeKxowu@hI*3G5QE8{l$XoLsA2{cS~dINWbI6LXu9mAcK1%xT`H$?T?bqU zx0S71KX*aGBi&ybF+wZ1sZvfVdmXA3xr*W6pE?$9pJF38vw!eLtNwk+zzY41UjOr&1Ft!NM%TLGvFk%p8oOdDDLX!0 N>H1Oj--ZAAe*iinSkC|e literal 0 HcmV?d00001 diff --git a/frontend/public/setup-agent-modius-1.png b/frontend/public/setup-agent-modius-1.png index 01ed645d08301a022d746bef6c4fe93dd6dac901..84b1adb8ca5b0699b13119cf6cdcd2e8f16999e7 100644 GIT binary patch literal 39891 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�ew*{aHs~Khwo#dHlIjU%g*M~j~|Q5 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 => + fetch(`${BACKEND_URL}/bridge/bridge_refill_requirements`, { + method: 'POST', + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + body: JSON.stringify(params), + signal, + }).then((response) => { + if (response.ok) return response.json(); + throw new Error( + `Failed to get bridge refill requirements for the following params: ${params}`, + ); + }); + +/** + * Execute bridge for the provided quote bundle id + */ +const executeBridge = async (id: string): Promise => + fetch(`${BACKEND_URL}/bridge/execute`, { + method: 'POST', + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + body: JSON.stringify({ id }), + }).then((response) => { + if (response.ok) return response.json(); + throw new Error( + `Failed to execute bridge quote for the following quote id: ${id}`, + ); + }); + +/** + * Get status of the bridge for the provided quote bundle id + */ +const getBridgeStatus = async ( + id: string, + signal: AbortSignal, +): Promise => + fetch(`${BACKEND_URL}/bridge/status/${id}`, { + method: 'GET', + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + signal, + }).then((response) => { + if (response.ok) return response.json(); + throw new Error( + `Failed to get bridge status for the following quote id: ${id}`, + ); + }); + +export const BridgeService = { + getBridgeRefillRequirements, + executeBridge, + getBridgeStatus, +}; diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index d26a8da35..f84ca69bc 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -1,6 +1,7 @@ import { MiddlewareChain, MiddlewareWalletResponse } from '@/client'; import { CONTENT_TYPE_JSON_UTF8 } from '@/constants/headers'; import { BACKEND_URL } from '@/constants/urls'; +import { SafeCreationResponse } from '@/types/Wallet'; /** * Returns a list of available wallets @@ -23,11 +24,17 @@ const createEoa = async () => throw new Error('Failed to create EOA'); }); -const createSafe = async (chain: MiddlewareChain, backup_owner?: string) => +/** + * @param initial_funds - Funds to be sent to master safe from master EOA + */ +const createSafe = async ( + chain: MiddlewareChain, + backup_owner?: string, +): Promise => fetch(`${BACKEND_URL}/wallet/safe`, { method: 'POST', headers: { ...CONTENT_TYPE_JSON_UTF8 }, - body: JSON.stringify({ chain, backup_owner, fund_amount: 0 }), + body: JSON.stringify({ chain, backup_owner, transfer_excess_assets: true }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create safe'); diff --git a/frontend/styles/globals.scss b/frontend/styles/globals.scss index 6863095e8..bbd893ec2 100644 --- a/frontend/styles/globals.scss +++ b/frontend/styles/globals.scss @@ -47,6 +47,10 @@ textarea, /* Scrollbar color when hovered */ } +.border-box { + box-sizing: border-box; +} + // antd overrides .ant-card { -webkit-app-region: no-drag; @@ -58,11 +62,6 @@ textarea, } } -.antd-card { - background-color: #FFFFFF; - overflow-y: scroll; -} - .balance { font-family: 'Inter'; font-weight: 900; @@ -142,6 +141,10 @@ textarea, margin-top: 4px !important; } +.mb-0 { + margin-bottom: 0px !important; +} + .mb-4 { margin-bottom: 4px !important; } @@ -150,6 +153,10 @@ textarea, margin-bottom: 8px !important; } +.mb-12 { + margin-bottom: 12px !important; +} + .mb-16 { margin-bottom: 16px !important; } @@ -178,11 +185,23 @@ textarea, margin-top: 12px !important; } +.mt-16 { + margin-top: 16px !important; +} + +.mt-24 { + margin-top: 24px !important; +} + // padding .p-0 { padding: 0 !important; } +.pl-4 { + padding-left: 4px !important; +} + .pl-16 { padding-left: 16px !important; } @@ -191,6 +210,22 @@ textarea, padding-right: 16px !important; } +.pt-16 { + padding-top: 16px !important; +} + +.pt-24 { + padding-top: 24px !important; +} + +.p-8 { + padding: 8px; +} + +.p-16 { + padding: 16px; +} + .p-24 { padding: 24px; } @@ -221,6 +256,7 @@ textarea, .text-center { text-align: center !important; } + .text-right { text-align: right !important; } @@ -230,6 +266,10 @@ textarea, color: #4D596A !important; } +.text-lighter { + color: #606F85 !important; +} + .text-right { text-align: right !important; } @@ -269,19 +309,28 @@ ul.alert-list { .w-full { width: 100% !important; } + .max-width-200 { max-width: 200px; } -.loading-ellipses:after { - overflow: hidden; +.loading-ellipses { display: inline-block; - vertical-align: bottom; - -webkit-animation: ellipsis steps(4, end) 900ms infinite; - animation: ellipsis steps(4, end) 900ms infinite; - content: "\2026"; - /* ascii code for the ellipsis character */ - width: 0px; + position: relative; /* Ensures absolute positioned :after is placed relative to this */ + white-space: nowrap; /* Prevents line breaks */ + margin-right: 16px; + + &:after { + overflow: hidden; + display: inline-block; + -webkit-animation: ellipsis steps(4, end) 1.5s infinite; + animation: ellipsis steps(4, end) 1.5s infinite; + content: "\2026"; /* ascii code for the ellipsis character */ + width: 0px; + position: absolute; + left: 100%; + white-space: nowrap; + } } .hover-underline { diff --git a/frontend/theme/index.ts b/frontend/theme/index.ts index 5f362f54e..48f0524df 100644 --- a/frontend/theme/index.ts +++ b/frontend/theme/index.ts @@ -18,6 +18,8 @@ export const mainTheme: ThemeConfig = { fontSize: 16, }, Button: { + contentFontSizeSM: 14, + paddingInlineSM: 12, fontSize: 16, fontSizeLG: 16, }, @@ -46,6 +48,13 @@ export const mainTheme: ThemeConfig = { Tag: { colorSuccess: '#135200', }, + List: { + colorBorder: '#DFE5EE', + }, + Steps: { + fontSize: 16, + colorError: '#CF1322', + }, }, }; diff --git a/frontend/types/Bridge.ts b/frontend/types/Bridge.ts new file mode 100644 index 000000000..de57c7d4f --- /dev/null +++ b/frontend/types/Bridge.ts @@ -0,0 +1,88 @@ +import { AddressBalanceRecord, MiddlewareChain } from '@/client'; +import { TokenSymbol } from '@/enums/Token'; + +import { Address } from './Address'; +import { Maybe, Nullable } from './Util'; + +/** + * Status of the each step in the bridging process. + * - process: the step is in progress (loading spinner) + * - wait: the step is waiting for the previous step to finish (grayed out) + * - finish: the step is finished (checked) + * - error: the step has failed (red cross) + */ +export type BridgingStepStatus = 'process' | 'wait' | 'finish' | 'error'; + +/** + * Execution status of each bridge step. + * For example, status of bridging ethereum to base. + * + * QUOTE_DONE: A quote is available. + * QUOTE_FAILED: Failed to request a quote. + * EXECUTION_PENDING: Execution submitted and pending to be finalized. + * EXECUTION_DONE: Execution finalized successfully. + * EXECUTION_FAILED: Execution failed. + */ +export type QuoteStatus = + | 'CREATED' + | 'QUOTE_DONE' + | 'QUOTE_FAILED' + | 'EXECUTION_PENDING' + | 'EXECUTION_DONE' + | 'EXECUTION_FAILED'; + +type BridgeFrom = { + chain: MiddlewareChain; + address: Address; + token: Address; +}; +type BridgeTo = BridgeFrom & { amount: string }; + +export type BridgeRefillRequirementsRequest = { + bridge_requests: { from: BridgeFrom; to: BridgeTo }[]; + force_update: boolean; +}; + +export type BridgeRefillRequirementsResponse = { + /** quote bundle Id */ + id: string; + balances: Partial<{ + [chain in MiddlewareChain]: AddressBalanceRecord; + }>; + bridge_total_requirements: Partial<{ + [chain in MiddlewareChain]: AddressBalanceRecord; + }>; + bridge_refill_requirements: Partial<{ + [chain in MiddlewareChain]: AddressBalanceRecord; + }>; + bridge_request_status: { message: Nullable; status: QuoteStatus }[]; + expiration_timestamp: number; + is_refill_required: boolean; +}; + +type QuoteRequestStatus = { + explorer_link: Maybe; + message: Nullable; + status: QuoteStatus; + tx_hash?: Maybe; +}; + +export type BridgeStatusResponse = { + id: string; + status: QuoteStatus; + bridge_request_status: QuoteRequestStatus[]; +}; + +export type TokenTransfer = { + fromSymbol: TokenSymbol; + fromAmount: string; + toSymbol: TokenSymbol; + toAmount: string; + decimals?: number; +}; + +export type CrossChainTransferDetails = { + fromChain: string; + toChain: string; + transfers: TokenTransfer[]; +}; diff --git a/frontend/types/Cookies.ts b/frontend/types/Cookies.ts deleted file mode 100644 index 0b2b63f9c..000000000 --- a/frontend/types/Cookies.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Cookies returned by agent-twitter-client - * scraper.getCookies() - */ -export type XCookie = { - key: string; - value: string; - domain?: string; - path?: string; - secure?: boolean; - httpOnly?: boolean; - sameSite?: string; - expires?: string; -}; diff --git a/frontend/types/Wallet.ts b/frontend/types/Wallet.ts new file mode 100644 index 000000000..aaa463e3d --- /dev/null +++ b/frontend/types/Wallet.ts @@ -0,0 +1,7 @@ +import { Address } from './Address'; + +export type SafeCreationResponse = { + safe: Address; + message: string; + create_tx?: string; +}; diff --git a/frontend/utils/address.ts b/frontend/utils/address.ts new file mode 100644 index 000000000..e58a846f8 --- /dev/null +++ b/frontend/utils/address.ts @@ -0,0 +1,11 @@ +import { toLower } from 'lodash'; + +import { Address } from '@/types/Address'; + +export const areAddressesEqual = ( + a1?: string | Address, + a2?: string | Address, +) => { + if (!a1 || !a2) return false; + return toLower(a1) === toLower(a2); +}; diff --git a/frontend/utils/calculations.ts b/frontend/utils/calculations.ts new file mode 100644 index 000000000..93aea0c8a --- /dev/null +++ b/frontend/utils/calculations.ts @@ -0,0 +1,9 @@ +/** + * Calculates the maximum value from a list of bigints. + * @param args - List of bigints to compare + * @returns The maximum value among the provided bigints + * @example bigintMax(1n, 2n, 3n); // returns 3n + */ +export function bigintMax(...args: bigint[]): bigint { + return args.reduce((max, val) => (val > max ? val : max)); +} diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts index 561eafb91..3c96e32e9 100644 --- a/frontend/utils/middlewareHelpers.ts +++ b/frontend/utils/middlewareHelpers.ts @@ -1,5 +1,6 @@ import { MiddlewareChain } from '@/client'; import { EvmChainId } from '@/enums/Chain'; +import { TokenSymbol } from '@/enums/Token'; /** * Converts middleware chain enums to chain ids @@ -64,3 +65,25 @@ export const asMiddlewareChain = (chainId?: EvmChainId | number) => { } throw new Error(`Invalid chain id: ${chainId}`); }; + +/** + * Converts token symbol to middleware chain enums + */ +export const toMiddlewareChainFromTokenSymbol = ( + tokenSymbol?: TokenSymbol, +): MiddlewareChain | undefined => { + switch (tokenSymbol) { + case 'ETH': + return MiddlewareChain.ETHEREUM; + case 'OLAS': + return MiddlewareChain.GNOSIS; + case 'CELO': + return MiddlewareChain.CELO; + case 'XDAI': + return MiddlewareChain.GNOSIS; + case 'WXDAI': + return MiddlewareChain.GNOSIS; + } + + throw new Error(`Invalid token symbol: ${tokenSymbol}`); +}; diff --git a/frontend/utils/numberFormatters.ts b/frontend/utils/numberFormatters.ts index d9b421acd..a607e39ac 100644 --- a/frontend/utils/numberFormatters.ts +++ b/frontend/utils/numberFormatters.ts @@ -1,8 +1,9 @@ import { BigNumberish, ethers } from 'ethers'; -import { round } from 'lodash'; +import { ceil } from 'lodash'; /** * Displays balance in a human readable format + * e.g. 10000000000 => 1.0B */ export const balanceFormat = ( balance: number | undefined, @@ -33,8 +34,9 @@ export const formatUnits = (value: BigNumberish, decimals = 18): string => { export const formatUnitsToNumber = ( value: BigNumberish, decimals = 18, + precision = 4, ): number => { - return round(parseFloat(formatUnits(value, decimals)), 4); + return ceil(parseFloat(formatUnits(value, decimals)), precision); }; /** diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index c7e36fc56..5198f900f 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -3,7 +3,9 @@ import { isEmpty, isNil } from 'lodash'; import { EnvProvisionType, ServiceTemplate } from '@/client'; import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; import { AgentType } from '@/enums/Agent'; +import { StakingProgramId } from '@/enums/StakingProgram'; import { ServicesService } from '@/service/Services'; +import { Address } from '@/types/Address'; import { Service } from '@/types/Service'; import { DeepPartial } from '@/types/Util'; @@ -25,17 +27,6 @@ export const updateServiceIfNeeded = async ( partialServiceTemplate.hash = serviceTemplate.hash; } - // Temporary: check if the service has the default description - if ( - serviceTemplate.agentType === AgentType.Memeooorr && - service.description === serviceTemplate.description - ) { - const xUsername = service.env_variables?.TWIKIT_USERNAME?.value; - if (xUsername) { - partialServiceTemplate.description = `Memeooorr @${xUsername}`; - } - } - // Temporary: check if the service has incorrect name if ( serviceTemplate.agentType === AgentType.Memeooorr && @@ -85,8 +76,8 @@ export const updateServiceIfNeeded = async ( if ( Object.entries(serviceHomeChainFundRequirements).some(([key, item]) => { return ( - templateFundRequirements?.[key]?.agent !== item.agent || - templateFundRequirements?.[key]?.safe !== item.safe + templateFundRequirements?.[key as Address]?.agent !== item.agent || + templateFundRequirements?.[key as Address]?.safe !== item.safe ); }) ) { @@ -105,6 +96,17 @@ export const updateServiceIfNeeded = async ( }); }; +export const onDummyServiceCreation = async ( + stakingProgramId: StakingProgramId, + serviceTemplateConfig: ServiceTemplate, +) => { + await ServicesService.createService({ + serviceTemplate: serviceTemplateConfig, + deploy: true, + stakingProgramId, + }); +}; + /** * Check if the token is a valid service id */ diff --git a/frontend/utils/x.ts b/frontend/utils/x.ts new file mode 100644 index 000000000..85c434698 --- /dev/null +++ b/frontend/utils/x.ts @@ -0,0 +1,18 @@ +import { MiddlewareServiceResponse, ServiceTemplate } from '@/client'; + +/** + * Get the X username from the service description. + * @param service - The service template object. + * @returns The X username or null if not found. + * + * @example + * getXUsername({ description: "Memeooorr @exampleUser" }) => "exampleUser" + */ +export const getXUsername = ( + service?: ServiceTemplate | MiddlewareServiceResponse, +) => { + if (!service) return null; + + const match = service.description.match(/@(\w+)/); + return match ? match[1] : null; +}; diff --git a/package.json b/package.json index f7cee5e3a..b6cbeec07 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "@fontsource/inter": "^5.0.17", "@tanstack/react-query": "^5.29.0", "adm-zip": "^0.5.12", - "agent-twitter-client": "^0.0.16", "antd": "^5.14.0", "axios": "^1.7.7", "child_process": "^1.0.2", @@ -75,7 +74,7 @@ "start:frontend": "cd frontend && yarn start", "test:frontend": "cd frontend && yarn test" }, - "version": "0.2.0-rc260", + "version": "0.2.0-rc173", "engine": { "node": ">=20", "yarn": ">=1.22.0", diff --git a/poetry.lock b/poetry.lock index 9a97f1216..bfd51dce0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand. [[package]] name = "aiohttp" @@ -134,13 +134,13 @@ files = [ [[package]] name = "anyio" -version = "4.8.0" +version = "4.9.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false python-versions = ">=3.9" files = [ - {file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"}, - {file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"}, + {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"}, + {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"}, ] [package.dependencies] @@ -150,10 +150,67 @@ sniffio = ">=1.1" typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [package.extras] -doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"] +test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"] trio = ["trio (>=0.26.1)"] +[[package]] +name = "argon2-cffi" +version = "23.1.0" +description = "Argon2 for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea"}, + {file = "argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08"}, +] + +[package.dependencies] +argon2-cffi-bindings = "*" + +[package.extras] +dev = ["argon2-cffi[tests,typing]", "tox (>4)"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-copybutton", "sphinx-notfound-page"] +tests = ["hypothesis", "pytest"] +typing = ["mypy"] + +[[package]] +name = "argon2-cffi-bindings" +version = "21.2.0" +description = "Low-level CFFI bindings for Argon2" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"}, + {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"}, + {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"}, + {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"}, + {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"}, +] + +[package.dependencies] +cffi = ">=1.0.1" + +[package.extras] +dev = ["cogapp", "pre-commit", "pytest", "wheel"] +tests = ["pytest"] + [[package]] name = "asn1crypto" version = "1.5.1" @@ -178,13 +235,13 @@ files = [ [[package]] name = "attrs" -version = "25.2.0" +version = "25.3.0" description = "Classes Without Boilerplate" optional = false python-versions = ">=3.8" files = [ - {file = "attrs-25.2.0-py3-none-any.whl", hash = "sha256:611344ff0a5fed735d86d7784610c84f8126b95e549bcad9ff61b4242f2d386b"}, - {file = "attrs-25.2.0.tar.gz", hash = "sha256:18a06db706db43ac232cce80443fcd9f2500702059ecf53489e3c5a3f417acaf"}, + {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"}, + {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"}, ] [package.extras] @@ -286,13 +343,13 @@ typecheck = ["mypy"] [[package]] name = "beautifulsoup4" -version = "4.13.3" +version = "4.13.4" description = "Screen-scraping library" optional = false python-versions = ">=3.7.0" files = [ - {file = "beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16"}, - {file = "beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b"}, + {file = "beautifulsoup4-4.13.4-py3-none-any.whl", hash = "sha256:9bbbb14bfde9d79f38b8cd5f8c7c85f4b8f2523190ebed90e950a8dea4cb1c4b"}, + {file = "beautifulsoup4-4.13.4.tar.gz", hash = "sha256:dbb3c4e1ceae6aefebdaf2423247260cd062430a410e38c66f2baa50a8437195"}, ] [package.dependencies] @@ -465,13 +522,13 @@ files = [ [[package]] name = "certifi" -version = "2025.1.31" +version = "2025.4.26" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"}, - {file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"}, + {file = "certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3"}, + {file = "certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6"}, ] [[package]] @@ -555,103 +612,103 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.4.1" +version = "3.4.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" files = [ - {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, - {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, - {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, - {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, - {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, - {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, - {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, - {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, - {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, - {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, + {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, + {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, ] [[package]] @@ -772,74 +829,74 @@ requests = "*" [[package]] name = "coverage" -version = "7.6.12" +version = "7.8.1" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.9" files = [ - {file = "coverage-7.6.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:704c8c8c6ce6569286ae9622e534b4f5b9759b6f2cd643f1c1a61f666d534fe8"}, - {file = "coverage-7.6.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ad7525bf0241e5502168ae9c643a2f6c219fa0a283001cee4cf23a9b7da75879"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06097c7abfa611c91edb9e6920264e5be1d6ceb374efb4986f38b09eed4cb2fe"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:220fa6c0ad7d9caef57f2c8771918324563ef0d8272c94974717c3909664e674"}, - {file = "coverage-7.6.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3688b99604a24492bcfe1c106278c45586eb819bf66a654d8a9a1433022fb2eb"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d1a987778b9c71da2fc8948e6f2656da6ef68f59298b7e9786849634c35d2c3c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cec6b9ce3bd2b7853d4a4563801292bfee40b030c05a3d29555fd2a8ee9bd68c"}, - {file = "coverage-7.6.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ace9048de91293e467b44bce0f0381345078389814ff6e18dbac8fdbf896360e"}, - {file = "coverage-7.6.12-cp310-cp310-win32.whl", hash = "sha256:ea31689f05043d520113e0552f039603c4dd71fa4c287b64cb3606140c66f425"}, - {file = "coverage-7.6.12-cp310-cp310-win_amd64.whl", hash = "sha256:676f92141e3c5492d2a1596d52287d0d963df21bf5e55c8b03075a60e1ddf8aa"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e18aafdfb3e9ec0d261c942d35bd7c28d031c5855dadb491d2723ba54f4c3015"}, - {file = "coverage-7.6.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:66fe626fd7aa5982cdebad23e49e78ef7dbb3e3c2a5960a2b53632f1f703ea45"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ef01d70198431719af0b1f5dcbefc557d44a190e749004042927b2a3fed0702"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e92ae5a289a4bc4c0aae710c0948d3c7892e20fd3588224ebe242039573bf0"}, - {file = "coverage-7.6.12-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e695df2c58ce526eeab11a2e915448d3eb76f75dffe338ea613c1201b33bab2f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d74c08e9aaef995f8c4ef6d202dbd219c318450fe2a76da624f2ebb9c8ec5d9f"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e995b3b76ccedc27fe4f477b349b7d64597e53a43fc2961db9d3fbace085d69d"}, - {file = "coverage-7.6.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b1f097878d74fe51e1ddd1be62d8e3682748875b461232cf4b52ddc6e6db0bba"}, - {file = "coverage-7.6.12-cp311-cp311-win32.whl", hash = "sha256:1f7ffa05da41754e20512202c866d0ebfc440bba3b0ed15133070e20bf5aeb5f"}, - {file = "coverage-7.6.12-cp311-cp311-win_amd64.whl", hash = "sha256:e216c5c45f89ef8971373fd1c5d8d1164b81f7f5f06bbf23c37e7908d19e8558"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad"}, - {file = "coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985"}, - {file = "coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3"}, - {file = "coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a"}, - {file = "coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95"}, - {file = "coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1"}, - {file = "coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e"}, - {file = "coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3"}, - {file = "coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc"}, - {file = "coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3"}, - {file = "coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e"}, - {file = "coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924"}, - {file = "coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827"}, - {file = "coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9"}, - {file = "coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3"}, - {file = "coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e7575ab65ca8399c8c4f9a7d61bbd2d204c8b8e447aab9d355682205c9dd948d"}, - {file = "coverage-7.6.12-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8161d9fbc7e9fe2326de89cd0abb9f3599bccc1287db0aba285cb68d204ce929"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a1e465f398c713f1b212400b4e79a09829cd42aebd360362cd89c5bdc44eb87"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f25d8b92a4e31ff1bd873654ec367ae811b3a943583e05432ea29264782dc32c"}, - {file = "coverage-7.6.12-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a936309a65cc5ca80fa9f20a442ff9e2d06927ec9a4f54bcba9c14c066323f2"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aa6f302a3a0b5f240ee201297fff0bbfe2fa0d415a94aeb257d8b461032389bd"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f973643ef532d4f9be71dd88cf7588936685fdb576d93a79fe9f65bc337d9d73"}, - {file = "coverage-7.6.12-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:78f5243bb6b1060aed6213d5107744c19f9571ec76d54c99cc15938eb69e0e86"}, - {file = "coverage-7.6.12-cp39-cp39-win32.whl", hash = "sha256:69e62c5034291c845fc4df7f8155e8544178b6c774f97a99e2734b05eb5bed31"}, - {file = "coverage-7.6.12-cp39-cp39-win_amd64.whl", hash = "sha256:b01a840ecc25dce235ae4c1b6a0daefb2a203dba0e6e980637ee9c2f6ee0df57"}, - {file = "coverage-7.6.12-pp39.pp310-none-any.whl", hash = "sha256:7e39e845c4d764208e7b8f6a21c541ade741e2c41afabdfa1caa28687a3c98cf"}, - {file = "coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953"}, - {file = "coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2"}, + {file = "coverage-7.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d7af3990490982fbd2437156c69edbe82b7edf99bc60302cceeeaf79afb886b8"}, + {file = "coverage-7.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5757a7b25fe48040fa120ba6597f5f885b01e323e0d13fe21ff95a70c0f76b7"}, + {file = "coverage-7.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8f105631835fdf191c971c4da93d27e732e028d73ecaa1a88f458d497d026cf"}, + {file = "coverage-7.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:21645788c5c2afa3df2d4b607638d86207b84cb495503b71e80e16b4c6b44e80"}, + {file = "coverage-7.8.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e93f36a5c9d995f40e9c4cd9bbabd83fd78705792fa250980256c93accd07bb6"}, + {file = "coverage-7.8.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d591f2ddad432b794f77dc1e94334a80015a3fc7fa07fd6aed8f40362083be5b"}, + {file = "coverage-7.8.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:be2b1a455b3ecfee20638289bb091a95216887d44924a41c28a601efac0916e8"}, + {file = "coverage-7.8.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:061a3bf679dc38fe34d3822f10a9977d548de86b440010beb1e3b44ba93d20f7"}, + {file = "coverage-7.8.1-cp310-cp310-win32.whl", hash = "sha256:12950b6373dc9dfe1ce22a8506ec29c82bfc5b38146ced0a222f38cf5d99a56d"}, + {file = "coverage-7.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:11e5ea0acd8cc5d23030c34dfb2eb6638ad886328df18cc69f8eefab73d1ece5"}, + {file = "coverage-7.8.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc6bebc15c3b275174c66cf4e1c949a94c5c2a3edaa2f193a1225548c52c771"}, + {file = "coverage-7.8.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a6c35afd5b912101fabf42975d92d750cfce33c571508a82ff334a133c40d5"}, + {file = "coverage-7.8.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b37729ba34c116a3b2b6fb99df5c37a4ca40e96f430070488fd7a1077ad44907"}, + {file = "coverage-7.8.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6424c716f4c38ff8f62b602e6b94cde478dadda542a1cb3fe2fe2520cc2aae3"}, + {file = "coverage-7.8.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bcfafb2809cd01be8ffe5f962e01b0fbe4cc1d74513434c52ff2dd05b86d492"}, + {file = "coverage-7.8.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e3f65da9701648d226b6b24ded3e2528b72075e48d7540968cd857c3bd4c5321"}, + {file = "coverage-7.8.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:173e16969f990688aae4b4487717c44330bc57fd8b61a6216ce8eeb827eb5c0d"}, + {file = "coverage-7.8.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3763b9a4bc128f72da5dcfd7fcc7c7d6644ed28e8f2db473ce1ef0dd37a43fa9"}, + {file = "coverage-7.8.1-cp311-cp311-win32.whl", hash = "sha256:d074380f587360d2500f3b065232c67ae248aaf739267807adbcd29b88bdf864"}, + {file = "coverage-7.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:cd21de85aa0e247b79c6c41f8b5541b54285550f2da6a9448d82b53234d3611b"}, + {file = "coverage-7.8.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2d8f844e837374a9497e11722d9eb9dfeb33b1b5d31136786c39a4c1a3073c6d"}, + {file = "coverage-7.8.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9cd54a762667c32112df5d6f059c5d61fa532ee06460948cc5bcbf60c502f5c9"}, + {file = "coverage-7.8.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:958b513e23286178b513a6b4d975fe9e7cddbcea6e5ebe8d836e4ef067577154"}, + {file = "coverage-7.8.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9b31756ea647b6ef53190f6b708ad0c4c2ea879bc17799ba5b0699eee59ecf7b"}, + {file = "coverage-7.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccad4e29ac1b6f75bfeedb2cac4860fe5bd9e0a2f04c3e3218f661fa389ab101"}, + {file = "coverage-7.8.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:452f3831c64f5f50260e18a89e613594590d6ceac5206a9b7d76ba43586b01b3"}, + {file = "coverage-7.8.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9296df6a33b8539cd753765eb5b47308602263a14b124a099cbcf5f770d7cf90"}, + {file = "coverage-7.8.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d52d79dfd3b410b153b6d65b0e3afe834eca2b969377f55ad73c67156d35af0d"}, + {file = "coverage-7.8.1-cp312-cp312-win32.whl", hash = "sha256:ebdf212e1ed85af63fa1a76d556c0a3c7b34348ffba6e145a64b15f003ad0a2b"}, + {file = "coverage-7.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:c04a7903644ccea8fa07c3e76db43ca31c8d453f93c5c94c0f9b82efca225543"}, + {file = "coverage-7.8.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd5c305faa2e69334a53061b3168987847dadc2449bab95735242a9bde92fde8"}, + {file = "coverage-7.8.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:af6b8cdf0857fd4e6460dd6639c37c3f82163127f6112c1942b5e6a52a477676"}, + {file = "coverage-7.8.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e233a56bbf99e4cb134c4f8e63b16c77714e3987daf2c5aa10c3ba8c4232d730"}, + {file = "coverage-7.8.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dabc70012fd7b58a8040a7bc1b5f71fd0e62e2138aefdd8367d3d24bf82c349"}, + {file = "coverage-7.8.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1f8e96455907496b3e4ea16f63bb578da31e17d2805278b193525e7714f17f2"}, + {file = "coverage-7.8.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0034ceec8e91fdaf77350901cc48f47efd00f23c220a3f9fc1187774ddf307cb"}, + {file = "coverage-7.8.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82db9344a07dd9106796b9fe8805425633146a7ea7fed5ed07c65a64d0bb79e1"}, + {file = "coverage-7.8.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9772c9e266b2ca4999180c12b90c8efb4c5c9ad3e55f301d78bc579af6467ad9"}, + {file = "coverage-7.8.1-cp313-cp313-win32.whl", hash = "sha256:6f24a1e2c373a77afae21bc512466a91e31251685c271c5309ee3e557f6e3e03"}, + {file = "coverage-7.8.1-cp313-cp313-win_amd64.whl", hash = "sha256:76a4e1d62505a21971968be61ae17cbdc5e0c483265a37f7ddbbc050f9c0b8ec"}, + {file = "coverage-7.8.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:35dd5d405a1d378c39f3f30f628a25b0b99f1b8e5bdd78275df2e7b0404892d7"}, + {file = "coverage-7.8.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:87b86a87f8de2e1bd0bcd45faf1b1edf54f988c8857157300e0336efcfb8ede6"}, + {file = "coverage-7.8.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce4553a573edb363d5db12be1c044826878bec039159d6d4eafe826ef773396d"}, + {file = "coverage-7.8.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db181a1896e0bad75b3bf4916c49fd3cf6751f9cc203fe0e0ecbee1fc43590fa"}, + {file = "coverage-7.8.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ce2606a171f9cf7c15a77ca61f979ffc0e0d92cd2fb18767cead58c1d19f58e"}, + {file = "coverage-7.8.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4fc4f7cff2495d6d112353c33a439230a6de0b7cd0c2578f1e8d75326f63d783"}, + {file = "coverage-7.8.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ff619c58322d9d6df0a859dc76c3532d7bdbc125cb040f7cd642141446b4f654"}, + {file = "coverage-7.8.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c0d6290a466a6f3fadf6add2dd4ec11deba4e1a6e3db2dd284edd497aadf802f"}, + {file = "coverage-7.8.1-cp313-cp313t-win32.whl", hash = "sha256:e4e893c7f7fb12271a667d5c1876710fae06d7580343afdb5f3fc4488b73209e"}, + {file = "coverage-7.8.1-cp313-cp313t-win_amd64.whl", hash = "sha256:41d142eefbc0bb3be160a77b2c0fbec76f345387676265052e224eb6c67b7af3"}, + {file = "coverage-7.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5102e17b81158de17d4b5bc363fcffd15231a38ef3f50b8e6fa01f0c6911194"}, + {file = "coverage-7.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3bd8e3753257e95e94f38c058627aba1581d51f674e3badf226283b2bdb8f8ca"}, + {file = "coverage-7.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d616b5a543c7d4deffa25eb8d8ae3d0d95097f08ac8b131600bb7fbf967ea0e2"}, + {file = "coverage-7.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f7a95b0dce364535a63fde0ec1b1ca36400037175d3b62ce04d85dbca5e33832"}, + {file = "coverage-7.8.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f82c1a1c1897d2293cb6c50f20fe8a9ea2add1a228eff479380917a1fe7bbb68"}, + {file = "coverage-7.8.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:62a13b372b65fa6e11685df9ca924bed23bab1d0f277f9b67be7536f253aaf17"}, + {file = "coverage-7.8.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe4877c24711458f7990392181be30166cc3ae72158036ecb48a73c30c99fb6f"}, + {file = "coverage-7.8.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:ae5e557aa92565d72f6d3196e878e7cbd6a6380e02a15eafe0af781bd767c10d"}, + {file = "coverage-7.8.1-cp39-cp39-win32.whl", hash = "sha256:87284f272746e31919302ab6211b16b41135109822c498f6e7b40a2f828e7836"}, + {file = "coverage-7.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:07fff2f2ce465fae27447432d39ce733476fbf8478de51fb4034c201e0c5da6d"}, + {file = "coverage-7.8.1-pp39.pp310.pp311-none-any.whl", hash = "sha256:adafe9d71a940927dd3ad8d487f521f11277f133568b7da622666ebd08923191"}, + {file = "coverage-7.8.1-py3-none-any.whl", hash = "sha256:e54b80885b0e61d346accc5709daf8762471a452345521cc9281604a907162c2"}, + {file = "coverage-7.8.1.tar.gz", hash = "sha256:d41d4da5f2871b1782c6b74948d2d37aac3a5b39b43a6ba31d736b97a02ae1f1"}, ] [package.extras] @@ -1015,21 +1072,26 @@ cython = ["cython"] [[package]] name = "deepdiff" -version = "8.3.0" +version = "8.5.0" description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "deepdiff-8.3.0-py3-none-any.whl", hash = "sha256:838acf1b17d228f4155bcb69bb265c41cbb5b2aba2575f07efa67ad9b9b7a0b5"}, - {file = "deepdiff-8.3.0.tar.gz", hash = "sha256:92a8d7c75a4b26b385ec0372269de258e20082307ccf74a4314341add3d88391"}, + {file = "deepdiff-8.5.0-py3-none-any.whl", hash = "sha256:d4599db637f36a1c285f5fdfc2cd8d38bde8d8be8636b65ab5e425b67c54df26"}, + {file = "deepdiff-8.5.0.tar.gz", hash = "sha256:a4dd3529fa8d4cd5b9cbb6e3ea9c95997eaa919ba37dac3966c1b8f872dc1cd1"}, ] [package.dependencies] -orderly-set = ">=5.3.0,<6" +orderly-set = ">=5.4.1,<6" [package.extras] -cli = ["click (==8.1.8)", "pyyaml (==6.0.2)"] +cli = ["click (>=8.1.0,<8.2.0)", "pyyaml (>=6.0.0,<6.1.0)"] +coverage = ["coverage (>=7.6.0,<7.7.0)"] +dev = ["bump2version (>=1.0.0,<1.1.0)", "ipdb (>=0.13.0,<0.14.0)", "jsonpickle (>=4.0.0,<4.1.0)", "nox (==2025.5.1)", "numpy (>=2.0,<3.0)", "numpy (>=2.2.0,<2.3.0)", "orjson (>=3.10.0,<3.11.0)", "pandas (>=2.2.0,<2.3.0)", "polars (>=1.21.0,<1.22.0)", "python-dateutil (>=2.9.0,<2.10.0)", "tomli (>=2.2.0,<2.3.0)", "tomli-w (>=1.2.0,<1.3.0)"] +docs = ["Sphinx (>=6.2.0,<6.3.0)", "sphinx-sitemap (>=2.6.0,<2.7.0)", "sphinxemoji (>=0.3.0,<0.4.0)"] optimize = ["orjson"] +static = ["flake8 (>=7.1.0,<7.2.0)", "flake8-pyproject (>=1.2.3,<1.3.0)", "pydantic (>=2.10.0,<2.11.0)"] +test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest-cov (>=6.0.0,<6.1.0)", "python-dotenv (>=1.0.0,<1.1.0)"] [[package]] name = "distro" @@ -1286,15 +1348,18 @@ test = ["hypothesis (>=4.43.0)", "mypy (==0.971)", "pytest (>=7.0.0)", "pytest-x [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, ] +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + [package.extras] test = ["pytest (>=6)"] @@ -1438,20 +1503,20 @@ files = [ [[package]] name = "googleapis-common-protos" -version = "1.69.1" +version = "1.70.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis_common_protos-1.69.1-py2.py3-none-any.whl", hash = "sha256:4077f27a6900d5946ee5a369fab9c8ded4c0ef1c6e880458ea2f70c14f7b70d5"}, - {file = "googleapis_common_protos-1.69.1.tar.gz", hash = "sha256:e20d2d8dda87da6fe7340afbbdf4f0bcb4c8fae7e6cadf55926c31f946b0b9b1"}, + {file = "googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8"}, + {file = "googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257"}, ] [package.dependencies] -protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0" [package.extras] -grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] +grpc = ["grpcio (>=1.44.0,<2.0.0)"] [[package]] name = "gql" @@ -1560,13 +1625,13 @@ protobuf = ["grpcio-tools (>=1.71.0)"] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, - {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, ] [[package]] @@ -1609,18 +1674,18 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.9" description = "A minimal low-level HTTP client." optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, - {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, ] [package.dependencies] certifi = "*" -h11 = ">=0.13,<0.15" +h11 = ">=0.16" [package.extras] asyncio = ["anyio (>=4.0,<5.0)"] @@ -1669,13 +1734,13 @@ all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2 [[package]] name = "importlib-metadata" -version = "8.6.1" +version = "8.7.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" files = [ - {file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"}, - {file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"}, + {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, + {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, ] [package.dependencies] @@ -1692,13 +1757,13 @@ type = ["pytest-mypy"] [[package]] name = "iniconfig" -version = "2.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] @@ -1872,149 +1937,140 @@ test = ["pytest"] [[package]] name = "lxml" -version = "5.3.1" +version = "5.4.0" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." optional = false python-versions = ">=3.6" files = [ - {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a4058f16cee694577f7e4dd410263cd0ef75644b43802a689c2b3c2a7e69453b"}, - {file = "lxml-5.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:364de8f57d6eda0c16dcfb999af902da31396949efa0e583e12675d09709881b"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:528f3a0498a8edc69af0559bdcf8a9f5a8bf7c00051a6ef3141fdcf27017bbf5"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db4743e30d6f5f92b6d2b7c86b3ad250e0bad8dee4b7ad8a0c44bfb276af89a3"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:17b5d7f8acf809465086d498d62a981fa6a56d2718135bb0e4aa48c502055f5c"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:928e75a7200a4c09e6efc7482a1337919cc61fe1ba289f297827a5b76d8969c2"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a997b784a639e05b9d4053ef3b20c7e447ea80814a762f25b8ed5a89d261eac"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:7b82e67c5feb682dbb559c3e6b78355f234943053af61606af126df2183b9ef9"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:f1de541a9893cf8a1b1db9bf0bf670a2decab42e3e82233d36a74eda7822b4c9"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:de1fc314c3ad6bc2f6bd5b5a5b9357b8c6896333d27fdbb7049aea8bd5af2d79"}, - {file = "lxml-5.3.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:7c0536bd9178f754b277a3e53f90f9c9454a3bd108b1531ffff720e082d824f2"}, - {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:68018c4c67d7e89951a91fbd371e2e34cd8cfc71f0bb43b5332db38497025d51"}, - {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aa826340a609d0c954ba52fd831f0fba2a4165659ab0ee1a15e4aac21f302406"}, - {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:796520afa499732191e39fc95b56a3b07f95256f2d22b1c26e217fb69a9db5b5"}, - {file = "lxml-5.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3effe081b3135237da6e4c4530ff2a868d3f80be0bda027e118a5971285d42d0"}, - {file = "lxml-5.3.1-cp310-cp310-win32.whl", hash = "sha256:a22f66270bd6d0804b02cd49dae2b33d4341015545d17f8426f2c4e22f557a23"}, - {file = "lxml-5.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:0bcfadea3cdc68e678d2b20cb16a16716887dd00a881e16f7d806c2138b8ff0c"}, - {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e220f7b3e8656ab063d2eb0cd536fafef396829cafe04cb314e734f87649058f"}, - {file = "lxml-5.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f2cfae0688fd01f7056a17367e3b84f37c545fb447d7282cf2c242b16262607"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67d2f8ad9dcc3a9e826bdc7802ed541a44e124c29b7d95a679eeb58c1c14ade8"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db0c742aad702fd5d0c6611a73f9602f20aec2007c102630c06d7633d9c8f09a"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:198bb4b4dd888e8390afa4f170d4fa28467a7eaf857f1952589f16cfbb67af27"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2a3e412ce1849be34b45922bfef03df32d1410a06d1cdeb793a343c2f1fd666"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b8969dbc8d09d9cd2ae06362c3bad27d03f433252601ef658a49bd9f2b22d79"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5be8f5e4044146a69c96077c7e08f0709c13a314aa5315981185c1f00235fe65"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:133f3493253a00db2c870d3740bc458ebb7d937bd0a6a4f9328373e0db305709"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:52d82b0d436edd6a1d22d94a344b9a58abd6c68c357ed44f22d4ba8179b37629"}, - {file = "lxml-5.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b6f92e35e2658a5ed51c6634ceb5ddae32053182851d8cad2a5bc102a359b33"}, - {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:203b1d3eaebd34277be06a3eb880050f18a4e4d60861efba4fb946e31071a295"}, - {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:155e1a5693cf4b55af652f5c0f78ef36596c7f680ff3ec6eb4d7d85367259b2c"}, - {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22ec2b3c191f43ed21f9545e9df94c37c6b49a5af0a874008ddc9132d49a2d9c"}, - {file = "lxml-5.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7eda194dd46e40ec745bf76795a7cccb02a6a41f445ad49d3cf66518b0bd9cff"}, - {file = "lxml-5.3.1-cp311-cp311-win32.whl", hash = "sha256:fb7c61d4be18e930f75948705e9718618862e6fc2ed0d7159b2262be73f167a2"}, - {file = "lxml-5.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:c809eef167bf4a57af4b03007004896f5c60bd38dc3852fcd97a26eae3d4c9e6"}, - {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:e69add9b6b7b08c60d7ff0152c7c9a6c45b4a71a919be5abde6f98f1ea16421c"}, - {file = "lxml-5.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e52e1b148867b01c05e21837586ee307a01e793b94072d7c7b91d2c2da02ffe"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4b382e0e636ed54cd278791d93fe2c4f370772743f02bcbe431a160089025c9"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2e49dc23a10a1296b04ca9db200c44d3eb32c8d8ec532e8c1fd24792276522a"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4399b4226c4785575fb20998dc571bc48125dc92c367ce2602d0d70e0c455eb0"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5412500e0dc5481b1ee9cf6b38bb3b473f6e411eb62b83dc9b62699c3b7b79f7"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c93ed3c998ea8472be98fb55aed65b5198740bfceaec07b2eba551e55b7b9ae"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:63d57fc94eb0bbb4735e45517afc21ef262991d8758a8f2f05dd6e4174944519"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:b450d7cabcd49aa7ab46a3c6aa3ac7e1593600a1a0605ba536ec0f1b99a04322"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:4df0ec814b50275ad6a99bc82a38b59f90e10e47714ac9871e1b223895825468"}, - {file = "lxml-5.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:d184f85ad2bb1f261eac55cddfcf62a70dee89982c978e92b9a74a1bfef2e367"}, - {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b725e70d15906d24615201e650d5b0388b08a5187a55f119f25874d0103f90dd"}, - {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a31fa7536ec1fb7155a0cd3a4e3d956c835ad0a43e3610ca32384d01f079ea1c"}, - {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3c3c8b55c7fc7b7e8877b9366568cc73d68b82da7fe33d8b98527b73857a225f"}, - {file = "lxml-5.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d61ec60945d694df806a9aec88e8f29a27293c6e424f8ff91c80416e3c617645"}, - {file = "lxml-5.3.1-cp312-cp312-win32.whl", hash = "sha256:f4eac0584cdc3285ef2e74eee1513a6001681fd9753b259e8159421ed28a72e5"}, - {file = "lxml-5.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:29bfc8d3d88e56ea0a27e7c4897b642706840247f59f4377d81be8f32aa0cfbf"}, - {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c093c7088b40d8266f57ed71d93112bd64c6724d31f0794c1e52cc4857c28e0e"}, - {file = "lxml-5.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0884e3f22d87c30694e625b1e62e6f30d39782c806287450d9dc2fdf07692fd"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1637fa31ec682cd5760092adfabe86d9b718a75d43e65e211d5931809bc111e7"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a364e8e944d92dcbf33b6b494d4e0fb3499dcc3bd9485beb701aa4b4201fa414"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:779e851fd0e19795ccc8a9bb4d705d6baa0ef475329fe44a13cf1e962f18ff1e"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c4393600915c308e546dc7003d74371744234e8444a28622d76fe19b98fa59d1"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:673b9d8e780f455091200bba8534d5f4f465944cbdd61f31dc832d70e29064a5"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2e4a570f6a99e96c457f7bec5ad459c9c420ee80b99eb04cbfcfe3fc18ec6423"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:71f31eda4e370f46af42fc9f264fafa1b09f46ba07bdbee98f25689a04b81c20"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:42978a68d3825eaac55399eb37a4d52012a205c0c6262199b8b44fcc6fd686e8"}, - {file = "lxml-5.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8b1942b3e4ed9ed551ed3083a2e6e0772de1e5e3aca872d955e2e86385fb7ff9"}, - {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:85c4f11be9cf08917ac2a5a8b6e1ef63b2f8e3799cec194417e76826e5f1de9c"}, - {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:231cf4d140b22a923b1d0a0a4e0b4f972e5893efcdec188934cc65888fd0227b"}, - {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5865b270b420eda7b68928d70bb517ccbe045e53b1a428129bb44372bf3d7dd5"}, - {file = "lxml-5.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dbf7bebc2275016cddf3c997bf8a0f7044160714c64a9b83975670a04e6d2252"}, - {file = "lxml-5.3.1-cp313-cp313-win32.whl", hash = "sha256:d0751528b97d2b19a388b302be2a0ee05817097bab46ff0ed76feeec24951f78"}, - {file = "lxml-5.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:91fb6a43d72b4f8863d21f347a9163eecbf36e76e2f51068d59cd004c506f332"}, - {file = "lxml-5.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:016b96c58e9a4528219bb563acf1aaaa8bc5452e7651004894a973f03b84ba81"}, - {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82a4bb10b0beef1434fb23a09f001ab5ca87895596b4581fd53f1e5145a8934a"}, - {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d68eeef7b4d08a25e51897dac29bcb62aba830e9ac6c4e3297ee7c6a0cf6439"}, - {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:f12582b8d3b4c6be1d298c49cb7ae64a3a73efaf4c2ab4e37db182e3545815ac"}, - {file = "lxml-5.3.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2df7ed5edeb6bd5590914cd61df76eb6cce9d590ed04ec7c183cf5509f73530d"}, - {file = "lxml-5.3.1-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:585c4dc429deebc4307187d2b71ebe914843185ae16a4d582ee030e6cfbb4d8a"}, - {file = "lxml-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:06a20d607a86fccab2fc15a77aa445f2bdef7b49ec0520a842c5c5afd8381576"}, - {file = "lxml-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:057e30d0012439bc54ca427a83d458752ccda725c1c161cc283db07bcad43cf9"}, - {file = "lxml-5.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4867361c049761a56bd21de507cab2c2a608c55102311d142ade7dab67b34f32"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dddf0fb832486cc1ea71d189cb92eb887826e8deebe128884e15020bb6e3f61"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bcc211542f7af6f2dfb705f5f8b74e865592778e6cafdfd19c792c244ccce19"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaca5a812f050ab55426c32177091130b1e49329b3f002a32934cd0245571307"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:236610b77589faf462337b3305a1be91756c8abc5a45ff7ca8f245a71c5dab70"}, - {file = "lxml-5.3.1-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:aed57b541b589fa05ac248f4cb1c46cbb432ab82cbd467d1c4f6a2bdc18aecf9"}, - {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:75fa3d6946d317ffc7016a6fcc44f42db6d514b7fdb8b4b28cbe058303cb6e53"}, - {file = "lxml-5.3.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:96eef5b9f336f623ffc555ab47a775495e7e8846dde88de5f941e2906453a1ce"}, - {file = "lxml-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:ef45f31aec9be01379fc6c10f1d9c677f032f2bac9383c827d44f620e8a88407"}, - {file = "lxml-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0611da6b07dd3720f492db1b463a4d1175b096b49438761cc9f35f0d9eaaef5"}, - {file = "lxml-5.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b2aca14c235c7a08558fe0a4786a1a05873a01e86b474dfa8f6df49101853a4e"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae82fce1d964f065c32c9517309f0c7be588772352d2f40b1574a214bd6e6098"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7aae7a3d63b935babfdc6864b31196afd5145878ddd22f5200729006366bc4d5"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8e0d177b1fe251c3b1b914ab64135475c5273c8cfd2857964b2e3bb0fe196a7"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:6c4dd3bfd0c82400060896717dd261137398edb7e524527438c54a8c34f736bf"}, - {file = "lxml-5.3.1-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f1208c1c67ec9e151d78aa3435aa9b08a488b53d9cfac9b699f15255a3461ef2"}, - {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c6aacf00d05b38a5069826e50ae72751cb5bc27bdc4d5746203988e429b385bb"}, - {file = "lxml-5.3.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:5881aaa4bf3a2d086c5f20371d3a5856199a0d8ac72dd8d0dbd7a2ecfc26ab73"}, - {file = "lxml-5.3.1-cp38-cp38-win32.whl", hash = "sha256:45fbb70ccbc8683f2fb58bea89498a7274af1d9ec7995e9f4af5604e028233fc"}, - {file = "lxml-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:7512b4d0fc5339d5abbb14d1843f70499cab90d0b864f790e73f780f041615d7"}, - {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5885bc586f1edb48e5d68e7a4b4757b5feb2a496b64f462b4d65950f5af3364f"}, - {file = "lxml-5.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1b92fe86e04f680b848fff594a908edfa72b31bfc3499ef7433790c11d4c8cd8"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a091026c3bf7519ab1e64655a3f52a59ad4a4e019a6f830c24d6430695b1cf6a"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ffb141361108e864ab5f1813f66e4e1164181227f9b1f105b042729b6c15125"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3715cdf0dd31b836433af9ee9197af10e3df41d273c19bb249230043667a5dfd"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88b72eb7222d918c967202024812c2bfb4048deeb69ca328363fb8e15254c549"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa59974880ab5ad8ef3afaa26f9bda148c5f39e06b11a8ada4660ecc9fb2feb3"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3bb8149840daf2c3f97cebf00e4ed4a65a0baff888bf2605a8d0135ff5cf764e"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_ppc64le.whl", hash = "sha256:0d6b2fa86becfa81f0a0271ccb9eb127ad45fb597733a77b92e8a35e53414914"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_s390x.whl", hash = "sha256:136bf638d92848a939fd8f0e06fcf92d9f2e4b57969d94faae27c55f3d85c05b"}, - {file = "lxml-5.3.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:89934f9f791566e54c1d92cdc8f8fd0009447a5ecdb1ec6b810d5f8c4955f6be"}, - {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8ade0363f776f87f982572c2860cc43c65ace208db49c76df0a21dde4ddd16e"}, - {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:bfbbab9316330cf81656fed435311386610f78b6c93cc5db4bebbce8dd146675"}, - {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:172d65f7c72a35a6879217bcdb4bb11bc88d55fb4879e7569f55616062d387c2"}, - {file = "lxml-5.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3c623923967f3e5961d272718655946e5322b8d058e094764180cdee7bab1af"}, - {file = "lxml-5.3.1-cp39-cp39-win32.whl", hash = "sha256:ce0930a963ff593e8bb6fda49a503911accc67dee7e5445eec972668e672a0f0"}, - {file = "lxml-5.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:f7b64fcd670bca8800bc10ced36620c6bbb321e7bc1214b9c0c0df269c1dddc2"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:afa578b6524ff85fb365f454cf61683771d0170470c48ad9d170c48075f86725"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67f5e80adf0aafc7b5454f2c1cb0cde920c9b1f2cbd0485f07cc1d0497c35c5d"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dd0b80ac2d8f13ffc906123a6f20b459cb50a99222d0da492360512f3e50f84"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:422c179022ecdedbe58b0e242607198580804253da220e9454ffe848daa1cfd2"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:524ccfded8989a6595dbdda80d779fb977dbc9a7bc458864fc9a0c2fc15dc877"}, - {file = "lxml-5.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48fd46bf7155def2e15287c6f2b133a2f78e2d22cdf55647269977b873c65499"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:05123fad495a429f123307ac6d8fd6f977b71e9a0b6d9aeeb8f80c017cb17131"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a243132767150a44e6a93cd1dde41010036e1cbc63cc3e9fe1712b277d926ce3"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c92ea6d9dd84a750b2bae72ff5e8cf5fdd13e58dda79c33e057862c29a8d5b50"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:2f1be45d4c15f237209bbf123a0e05b5d630c8717c42f59f31ea9eae2ad89394"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:a83d3adea1e0ee36dac34627f78ddd7f093bb9cfc0a8e97f1572a949b695cb98"}, - {file = "lxml-5.3.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:3edbb9c9130bac05d8c3fe150c51c337a471cc7fdb6d2a0a7d3a88e88a829314"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2f23cf50eccb3255b6e913188291af0150d89dab44137a69e14e4dcb7be981f1"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df7e5edac4778127f2bf452e0721a58a1cfa4d1d9eac63bdd650535eb8543615"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:094b28ed8a8a072b9e9e2113a81fda668d2053f2ca9f2d202c2c8c7c2d6516b1"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:514fe78fc4b87e7a7601c92492210b20a1b0c6ab20e71e81307d9c2e377c64de"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8fffc08de02071c37865a155e5ea5fce0282e1546fd5bde7f6149fcaa32558ac"}, - {file = "lxml-5.3.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4b0d5cdba1b655d5b18042ac9c9ff50bda33568eb80feaaca4fc237b9c4fbfde"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:3031e4c16b59424e8d78522c69b062d301d951dc55ad8685736c3335a97fc270"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb659702a45136c743bc130760c6f137870d4df3a9e14386478b8a0511abcfca"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a11b16a33656ffc43c92a5343a28dc71eefe460bcc2a4923a96f292692709f6"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c5ae125276f254b01daa73e2c103363d3e99e3e10505686ac7d9d2442dd4627a"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c76722b5ed4a31ba103e0dc77ab869222ec36efe1a614e42e9bcea88a36186fe"}, - {file = "lxml-5.3.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:33e06717c00c788ab4e79bc4726ecc50c54b9bfb55355eae21473c145d83c2d2"}, - {file = "lxml-5.3.1.tar.gz", hash = "sha256:106b7b5d2977b339f1e97efe2778e2ab20e99994cbb0ec5e55771ed0795920c8"}, + {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e7bc6df34d42322c5289e37e9971d6ed114e3776b45fa879f734bded9d1fea9c"}, + {file = "lxml-5.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6854f8bd8a1536f8a1d9a3655e6354faa6406621cf857dc27b681b69860645c7"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:696ea9e87442467819ac22394ca36cb3d01848dad1be6fac3fb612d3bd5a12cf"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ef80aeac414f33c24b3815ecd560cee272786c3adfa5f31316d8b349bfade28"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b9c2754cef6963f3408ab381ea55f47dabc6f78f4b8ebb0f0b25cf1ac1f7609"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7a62cc23d754bb449d63ff35334acc9f5c02e6dae830d78dab4dd12b78a524f4"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f82125bc7203c5ae8633a7d5d20bcfdff0ba33e436e4ab0abc026a53a8960b7"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b67319b4aef1a6c56576ff544b67a2a6fbd7eaee485b241cabf53115e8908b8f"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:a8ef956fce64c8551221f395ba21d0724fed6b9b6242ca4f2f7beb4ce2f41997"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:0a01ce7d8479dce84fc03324e3b0c9c90b1ece9a9bb6a1b6c9025e7e4520e78c"}, + {file = "lxml-5.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:91505d3ddebf268bb1588eb0f63821f738d20e1e7f05d3c647a5ca900288760b"}, + {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a3bcdde35d82ff385f4ede021df801b5c4a5bcdfb61ea87caabcebfc4945dc1b"}, + {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:aea7c06667b987787c7d1f5e1dfcd70419b711cdb47d6b4bb4ad4b76777a0563"}, + {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7fb111eef4d05909b82152721a59c1b14d0f365e2be4c742a473c5d7372f4f5"}, + {file = "lxml-5.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43d549b876ce64aa18b2328faff70f5877f8c6dede415f80a2f799d31644d776"}, + {file = "lxml-5.4.0-cp310-cp310-win32.whl", hash = "sha256:75133890e40d229d6c5837b0312abbe5bac1c342452cf0e12523477cd3aa21e7"}, + {file = "lxml-5.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:de5b4e1088523e2b6f730d0509a9a813355b7f5659d70eb4f319c76beea2e250"}, + {file = "lxml-5.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:98a3912194c079ef37e716ed228ae0dcb960992100461b704aea4e93af6b0bb9"}, + {file = "lxml-5.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ea0252b51d296a75f6118ed0d8696888e7403408ad42345d7dfd0d1e93309a7"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b92b69441d1bd39f4940f9eadfa417a25862242ca2c396b406f9272ef09cdcaa"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20e16c08254b9b6466526bc1828d9370ee6c0d60a4b64836bc3ac2917d1e16df"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7605c1c32c3d6e8c990dd28a0970a3cbbf1429d5b92279e37fda05fb0c92190e"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ecf4c4b83f1ab3d5a7ace10bafcb6f11df6156857a3c418244cef41ca9fa3e44"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0cef4feae82709eed352cd7e97ae062ef6ae9c7b5dbe3663f104cd2c0e8d94ba"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:df53330a3bff250f10472ce96a9af28628ff1f4efc51ccba351a8820bca2a8ba"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_ppc64le.whl", hash = "sha256:aefe1a7cb852fa61150fcb21a8c8fcea7b58c4cb11fbe59c97a0a4b31cae3c8c"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_s390x.whl", hash = "sha256:ef5a7178fcc73b7d8c07229e89f8eb45b2908a9238eb90dcfc46571ccf0383b8"}, + {file = "lxml-5.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d2ed1b3cb9ff1c10e6e8b00941bb2e5bb568b307bfc6b17dffbbe8be5eecba86"}, + {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:72ac9762a9f8ce74c9eed4a4e74306f2f18613a6b71fa065495a67ac227b3056"}, + {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f5cb182f6396706dc6cc1896dd02b1c889d644c081b0cdec38747573db88a7d7"}, + {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:3a3178b4873df8ef9457a4875703488eb1622632a9cee6d76464b60e90adbfcd"}, + {file = "lxml-5.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e094ec83694b59d263802ed03a8384594fcce477ce484b0cbcd0008a211ca751"}, + {file = "lxml-5.4.0-cp311-cp311-win32.whl", hash = "sha256:4329422de653cdb2b72afa39b0aa04252fca9071550044904b2e7036d9d97fe4"}, + {file = "lxml-5.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd3be6481ef54b8cfd0e1e953323b7aa9d9789b94842d0e5b142ef4bb7999539"}, + {file = "lxml-5.4.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b5aff6f3e818e6bdbbb38e5967520f174b18f539c2b9de867b1e7fde6f8d95a4"}, + {file = "lxml-5.4.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:942a5d73f739ad7c452bf739a62a0f83e2578afd6b8e5406308731f4ce78b16d"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:460508a4b07364d6abf53acaa0a90b6d370fafde5693ef37602566613a9b0779"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:529024ab3a505fed78fe3cc5ddc079464e709f6c892733e3f5842007cec8ac6e"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ca56ebc2c474e8f3d5761debfd9283b8b18c76c4fc0967b74aeafba1f5647f9"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a81e1196f0a5b4167a8dafe3a66aa67c4addac1b22dc47947abd5d5c7a3f24b5"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00b8686694423ddae324cf614e1b9659c2edb754de617703c3d29ff568448df5"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c5681160758d3f6ac5b4fea370495c48aac0989d6a0f01bb9a72ad8ef5ab75c4"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_ppc64le.whl", hash = "sha256:2dc191e60425ad70e75a68c9fd90ab284df64d9cd410ba8d2b641c0c45bc006e"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_s390x.whl", hash = "sha256:67f779374c6b9753ae0a0195a892a1c234ce8416e4448fe1e9f34746482070a7"}, + {file = "lxml-5.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:79d5bfa9c1b455336f52343130b2067164040604e41f6dc4d8313867ed540079"}, + {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3d3c30ba1c9b48c68489dc1829a6eede9873f52edca1dda900066542528d6b20"}, + {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1af80c6316ae68aded77e91cd9d80648f7dd40406cef73df841aa3c36f6907c8"}, + {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4d885698f5019abe0de3d352caf9466d5de2baded00a06ef3f1216c1a58ae78f"}, + {file = "lxml-5.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:aea53d51859b6c64e7c51d522c03cc2c48b9b5d6172126854cc7f01aa11f52bc"}, + {file = "lxml-5.4.0-cp312-cp312-win32.whl", hash = "sha256:d90b729fd2732df28130c064aac9bb8aff14ba20baa4aee7bd0795ff1187545f"}, + {file = "lxml-5.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1dc4ca99e89c335a7ed47d38964abcb36c5910790f9bd106f2a8fa2ee0b909d2"}, + {file = "lxml-5.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:773e27b62920199c6197130632c18fb7ead3257fce1ffb7d286912e56ddb79e0"}, + {file = "lxml-5.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ce9c671845de9699904b1e9df95acfe8dfc183f2310f163cdaa91a3535af95de"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9454b8d8200ec99a224df8854786262b1bd6461f4280064c807303c642c05e76"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cccd007d5c95279e529c146d095f1d39ac05139de26c098166c4beb9374b0f4d"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fce1294a0497edb034cb416ad3e77ecc89b313cff7adbee5334e4dc0d11f422"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24974f774f3a78ac12b95e3a20ef0931795ff04dbb16db81a90c37f589819551"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:497cab4d8254c2a90bf988f162ace2ddbfdd806fce3bda3f581b9d24c852e03c"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:e794f698ae4c5084414efea0f5cc9f4ac562ec02d66e1484ff822ef97c2cadff"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_ppc64le.whl", hash = "sha256:2c62891b1ea3094bb12097822b3d44b93fc6c325f2043c4d2736a8ff09e65f60"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_s390x.whl", hash = "sha256:142accb3e4d1edae4b392bd165a9abdee8a3c432a2cca193df995bc3886249c8"}, + {file = "lxml-5.4.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:1a42b3a19346e5601d1b8296ff6ef3d76038058f311902edd574461e9c036982"}, + {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4291d3c409a17febf817259cb37bc62cb7eb398bcc95c1356947e2871911ae61"}, + {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4f5322cf38fe0e21c2d73901abf68e6329dc02a4994e483adbcf92b568a09a54"}, + {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:0be91891bdb06ebe65122aa6bf3fc94489960cf7e03033c6f83a90863b23c58b"}, + {file = "lxml-5.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:15a665ad90054a3d4f397bc40f73948d48e36e4c09f9bcffc7d90c87410e478a"}, + {file = "lxml-5.4.0-cp313-cp313-win32.whl", hash = "sha256:d5663bc1b471c79f5c833cffbc9b87d7bf13f87e055a5c86c363ccd2348d7e82"}, + {file = "lxml-5.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:bcb7a1096b4b6b24ce1ac24d4942ad98f983cd3810f9711bcd0293f43a9d8b9f"}, + {file = "lxml-5.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7be701c24e7f843e6788353c055d806e8bd8466b52907bafe5d13ec6a6dbaecd"}, + {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb54f7c6bafaa808f27166569b1511fc42701a7713858dddc08afdde9746849e"}, + {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97dac543661e84a284502e0cf8a67b5c711b0ad5fb661d1bd505c02f8cf716d7"}, + {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:c70e93fba207106cb16bf852e421c37bbded92acd5964390aad07cb50d60f5cf"}, + {file = "lxml-5.4.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9c886b481aefdf818ad44846145f6eaf373a20d200b5ce1a5c8e1bc2d8745410"}, + {file = "lxml-5.4.0-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:fa0e294046de09acd6146be0ed6727d1f42ded4ce3ea1e9a19c11b6774eea27c"}, + {file = "lxml-5.4.0-cp36-cp36m-win32.whl", hash = "sha256:61c7bbf432f09ee44b1ccaa24896d21075e533cd01477966a5ff5a71d88b2f56"}, + {file = "lxml-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7ce1a171ec325192c6a636b64c94418e71a1964f56d002cc28122fceff0b6121"}, + {file = "lxml-5.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:795f61bcaf8770e1b37eec24edf9771b307df3af74d1d6f27d812e15a9ff3872"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29f451a4b614a7b5b6c2e043d7b64a15bd8304d7e767055e8ab68387a8cacf4e"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aa412a82e460571fad592d0f93ce9935a20090029ba08eca05c614f99b0cc92"}, + {file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:c5d32f5284012deaccd37da1e2cd42f081feaa76981f0eaa474351b68df813c5"}, + {file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:31e63621e073e04697c1b2d23fcb89991790eef370ec37ce4d5d469f40924ed6"}, + {file = "lxml-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:be2ba4c3c5b7900246a8f866580700ef0d538f2ca32535e991027bdaba944063"}, + {file = "lxml-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:09846782b1ef650b321484ad429217f5154da4d6e786636c38e434fa32e94e49"}, + {file = "lxml-5.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eaf24066ad0b30917186420d51e2e3edf4b0e2ea68d8cd885b14dc8afdcf6556"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b31a3a77501d86d8ade128abb01082724c0dfd9524f542f2f07d693c9f1175f"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e108352e203c7afd0eb91d782582f00a0b16a948d204d4dec8565024fafeea5"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a11a96c3b3f7551c8a8109aa65e8594e551d5a84c76bf950da33d0fb6dfafab7"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:ca755eebf0d9e62d6cb013f1261e510317a41bf4650f22963474a663fdfe02aa"}, + {file = "lxml-5.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:4cd915c0fb1bed47b5e6d6edd424ac25856252f09120e3e8ba5154b6b921860e"}, + {file = "lxml-5.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:226046e386556a45ebc787871d6d2467b32c37ce76c2680f5c608e25823ffc84"}, + {file = "lxml-5.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:b108134b9667bcd71236c5a02aad5ddd073e372fb5d48ea74853e009fe38acb6"}, + {file = "lxml-5.4.0-cp38-cp38-win32.whl", hash = "sha256:1320091caa89805df7dcb9e908add28166113dcd062590668514dbd510798c88"}, + {file = "lxml-5.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:073eb6dcdf1f587d9b88c8c93528b57eccda40209cf9be549d469b942b41d70b"}, + {file = "lxml-5.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bda3ea44c39eb74e2488297bb39d47186ed01342f0022c8ff407c250ac3f498e"}, + {file = "lxml-5.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9ceaf423b50ecfc23ca00b7f50b64baba85fb3fb91c53e2c9d00bc86150c7e40"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:664cdc733bc87449fe781dbb1f309090966c11cc0c0cd7b84af956a02a8a4729"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67ed8a40665b84d161bae3181aa2763beea3747f748bca5874b4af4d75998f87"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b4a3bd174cc9cdaa1afbc4620c049038b441d6ba07629d89a83b408e54c35cd"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:b0989737a3ba6cf2a16efb857fb0dfa20bc5c542737fddb6d893fde48be45433"}, + {file = "lxml-5.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:dc0af80267edc68adf85f2a5d9be1cdf062f973db6790c1d065e45025fa26140"}, + {file = "lxml-5.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:639978bccb04c42677db43c79bdaa23785dc7f9b83bfd87570da8207872f1ce5"}, + {file = "lxml-5.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a99d86351f9c15e4a901fc56404b485b1462039db59288b203f8c629260a142"}, + {file = "lxml-5.4.0-cp39-cp39-win32.whl", hash = "sha256:3e6d5557989cdc3ebb5302bbdc42b439733a841891762ded9514e74f60319ad6"}, + {file = "lxml-5.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:a8c9b7f16b63e65bbba889acb436a1034a82d34fa09752d754f88d708eca80e1"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:1b717b00a71b901b4667226bba282dd462c42ccf618ade12f9ba3674e1fabc55"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27a9ded0f0b52098ff89dd4c418325b987feed2ea5cc86e8860b0f844285d740"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7ce10634113651d6f383aa712a194179dcd496bd8c41e191cec2099fa09de5"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53370c26500d22b45182f98847243efb518d268374a9570409d2e2276232fd37"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c6364038c519dffdbe07e3cf42e6a7f8b90c275d4d1617a69bb59734c1a2d571"}, + {file = "lxml-5.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b12cb6527599808ada9eb2cd6e0e7d3d8f13fe7bbb01c6311255a15ded4c7ab4"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5f11a1526ebd0dee85e7b1e39e39a0cc0d9d03fb527f56d8457f6df48a10dc0c"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b4afaf38bf79109bb060d9016fad014a9a48fb244e11b94f74ae366a64d252"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de6f6bb8a7840c7bf216fb83eec4e2f79f7325eca8858167b68708b929ab2172"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5cca36a194a4eb4e2ed6be36923d3cffd03dcdf477515dea687185506583d4c9"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:b7c86884ad23d61b025989d99bfdd92a7351de956e01c61307cb87035960bcb1"}, + {file = "lxml-5.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:53d9469ab5460402c19553b56c3648746774ecd0681b1b27ea74d5d8a3ef5590"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:56dbdbab0551532bb26c19c914848d7251d73edb507c3079d6805fa8bba5b706"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14479c2ad1cb08b62bb941ba8e0e05938524ee3c3114644df905d2331c76cd57"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32697d2ea994e0db19c1df9e40275ffe84973e4232b5c274f47e7c1ec9763cdd"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:24f6df5f24fc3385f622c0c9d63fe34604893bc1a5bdbb2dbf5870f85f9a404a"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:151d6c40bc9db11e960619d2bf2ec5829f0aaffb10b41dcf6ad2ce0f3c0b2325"}, + {file = "lxml-5.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:4025bf2884ac4370a3243c5aa8d66d3cb9e15d3ddd0af2d796eccc5f0244390e"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9459e6892f59ecea2e2584ee1058f5d8f629446eab52ba2305ae13a32a059530"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47fb24cc0f052f0576ea382872b3fc7e1f7e3028e53299ea751839418ade92a6"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50441c9de951a153c698b9b99992e806b71c1f36d14b154592580ff4a9d0d877"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:ab339536aa798b1e17750733663d272038bf28069761d5be57cb4a9b0137b4f8"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9776af1aad5a4b4a1317242ee2bea51da54b2a7b7b48674be736d463c999f37d"}, + {file = "lxml-5.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:63e7968ff83da2eb6fdda967483a7a023aa497d85ad8f05c3ad9b1f2e8c84987"}, + {file = "lxml-5.4.0.tar.gz", hash = "sha256:d12832e1dbea4be280b22fd0ea7c9b87f0d8fc51ba06e92dc62d52f804f78ebd"}, ] [package.extras] @@ -2250,7 +2306,7 @@ nicer-shell = ["ipython"] [[package]] name = "olas-operate-middleware" -version = "0.3.2" +version = "0.4.0" description = "" optional = false python-versions = "<3.12,>=3.9" @@ -2259,6 +2315,7 @@ develop = false [package.dependencies] aiohttp = "3.9.5" +argon2-cffi = "==23.1.0" clea = "==0.1.0rc4" cytoolz = "==0.12.3" deepdiff = "^8.0.1" @@ -2278,11 +2335,11 @@ hexbytes = "==0.3.1" ipfshttpclient = "==0.8.0a2" jsonschema = "==4.3.3" multidict = "==6.0.5" -open-aea-cli-ipfs = "==1.64.0" -open-aea-ledger-cosmos = "==1.64.0" -open-aea-ledger-ethereum = "==1.64.0" -open-aea-ledger-ethereum-flashbots = "==1.64.0" -open-autonomy = "==0.19.4" +open-aea-cli-ipfs = "==1.65.0" +open-aea-ledger-cosmos = "==1.65.0" +open-aea-ledger-ethereum = "==1.65.0" +open-aea-ledger-ethereum-flashbots = "==1.65.0" +open-autonomy = "==0.19.8" psutil = "^5.9.8" pyinstaller = "^6.8.0" requests-toolbelt = "1.0.0" @@ -2294,23 +2351,23 @@ web3 = "==6.1.0" [package.source] type = "git" url = "https://github.com/valory-xyz/olas-operate-middleware.git" -reference = "6cfb306a4c4234d4c570fba9209159749c1ce71f" -resolved_reference = "6cfb306a4c4234d4c570fba9209159749c1ce71f" +reference = "920957b1871a533a3a63f1162d9c6d10625226a8" +resolved_reference = "920957b1871a533a3a63f1162d9c6d10625226a8" [[package]] name = "open-aea" -version = "1.64.0" +version = "1.65.0" description = "Open Autonomous Economic Agent framework (without vendor lock-in)" optional = false python-versions = ">=3.8" files = [ - {file = "open_aea-1.64.0-py3-none-any.whl", hash = "sha256:aa1f4c125ede428a17147f3428b42b968503139bd8041a87c3b38b151f8ed9f6"}, - {file = "open_aea-1.64.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9f6eefa9000208e625f61e0bab8070fe244a4dc948de46ad2cbba48e69ff803b"}, - {file = "open_aea-1.64.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:4e627fba9ec368182cfec54c26c961cb399a468da9a2d49c61bac7f9883f88f4"}, - {file = "open_aea-1.64.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:a320979d530aadad6a7d87e488459013ee1c070fe163ee5c3c1cdb01b63e9be7"}, - {file = "open_aea-1.64.0-py3-none-win32.whl", hash = "sha256:3501fbcbe4ec3b34d2f5dcd91403ee4dbd089a0afc98b21baf7f6b6607d64005"}, - {file = "open_aea-1.64.0-py3-none-win_amd64.whl", hash = "sha256:948d52ae67b867987588d6ac462fe35d4782a0696a9fdc191ab028634365f93b"}, - {file = "open_aea-1.64.0.tar.gz", hash = "sha256:d39b997fe8c29403b9266e548cbd01aeea5725fbb397c42e718af50b93b4c5e5"}, + {file = "open_aea-1.65.0-py3-none-any.whl", hash = "sha256:e6353ccc29014e1015acabc4b4b83756bbfc955d6f0a8fa9e8104f3daef5eb5a"}, + {file = "open_aea-1.65.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:bdba7028bb7c85e1ec267d0dbdf372843a2492c5cf220c4d6badc45bd206c31d"}, + {file = "open_aea-1.65.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:d0195e1eeae6620cf04898800fad0bc89f460c5d4c4e89e5e54f8d4ced7337b2"}, + {file = "open_aea-1.65.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:fc636b22af8c3160911e857692126ab7dadf5af834ed5b52559e4ab9c3d4935f"}, + {file = "open_aea-1.65.0-py3-none-win32.whl", hash = "sha256:b3bddcb64ec1852f59d6c730ad1ee825b0243d8bd4d25c744b5087ae40f0e04d"}, + {file = "open_aea-1.65.0-py3-none-win_amd64.whl", hash = "sha256:5fdba41e7ffafd47e56e83f20fec4d764b5db5a57fba56c39c134ef1c602d479"}, + {file = "open_aea-1.65.0.tar.gz", hash = "sha256:7be549fd41ae423f527146c80435bf4a5002dd85d2e4cef368f344e8641aab80"}, ] [package.dependencies] @@ -2338,13 +2395,13 @@ test-tools = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>= [[package]] name = "open-aea-cli-ipfs" -version = "1.64.0" +version = "1.65.0" description = "CLI extension for open AEA framework wrapping IPFS functionality." optional = false python-versions = "*" files = [ - {file = "open_aea_cli_ipfs-1.64.0-py3-none-any.whl", hash = "sha256:79fb5373100735efa3b294ce1ab643d2dd1e2502b4e11da449131d7aee082ff6"}, - {file = "open_aea_cli_ipfs-1.64.0.tar.gz", hash = "sha256:69088d5c8b192ef11ae692a1ae4dab4fa934ba466e9033df76195985aa17f773"}, + {file = "open_aea_cli_ipfs-1.65.0-py3-none-any.whl", hash = "sha256:5f1e730d0821bf5b85c3dc8cc049e94a885b7ea042e8cf1cf573956576d91a49"}, + {file = "open_aea_cli_ipfs-1.65.0.tar.gz", hash = "sha256:2e9875b1b334aa3f949fa2e52c4870f697c9550d02bbde1847fff603fb069205"}, ] [package.dependencies] @@ -2369,13 +2426,13 @@ web3 = ">=6.0.0,<7" [[package]] name = "open-aea-ledger-cosmos" -version = "1.64.0" +version = "1.65.0" description = "Python package wrapping the public and private key cryptography and ledger api of Cosmos." optional = false python-versions = "*" files = [ - {file = "open_aea_ledger_cosmos-1.64.0-py3-none-any.whl", hash = "sha256:1bc4752e696871588c391659c0df5907eccc4d938f3b14a4fa5346cc04ad953f"}, - {file = "open_aea_ledger_cosmos-1.64.0.tar.gz", hash = "sha256:c836c753c8a4150ea49f19723dce808e357243bdebceb556dbc46abb0d2a6f14"}, + {file = "open_aea_ledger_cosmos-1.65.0-py3-none-any.whl", hash = "sha256:58a5816c2dc7657cf26a93a934958f3f1b5f7744664770cf182903cd74a0aa22"}, + {file = "open_aea_ledger_cosmos-1.65.0.tar.gz", hash = "sha256:8da7f5081ff569eb4caa9a7c2a3afe9c03aa9d0d81f060746f949596ae344304"}, ] [package.dependencies] @@ -2387,13 +2444,13 @@ pycryptodome = ">=3.10.1,<4.0.0" [[package]] name = "open-aea-ledger-ethereum" -version = "1.64.0" +version = "1.65.0" description = "Python package wrapping the public and private key cryptography and ledger api of Ethereum." optional = false python-versions = "*" files = [ - {file = "open_aea_ledger_ethereum-1.64.0-py3-none-any.whl", hash = "sha256:0d34ef8292c437a3f8102bd7489d12b5f5000013639bee71f5fb09e84eabe413"}, - {file = "open_aea_ledger_ethereum-1.64.0.tar.gz", hash = "sha256:5de862d87be2ef47b8f4c7de7802956b3f214f9bfbfc8369dfcb638702b070b8"}, + {file = "open_aea_ledger_ethereum-1.65.0-py3-none-any.whl", hash = "sha256:88d0f571a2a0f247cfe581ac8a4273541da1bf4e9e7ae88197ed24e945f26ba4"}, + {file = "open_aea_ledger_ethereum-1.65.0.tar.gz", hash = "sha256:7ee3e58e6eee025008f7f2550fdfc315b41bb1e3d961187ef760a196995134c1"}, ] [package.dependencies] @@ -2404,28 +2461,28 @@ web3 = ">=6.0.0,<7" [[package]] name = "open-aea-ledger-ethereum-flashbots" -version = "1.64.0" +version = "1.65.0" description = "Python package extending the default open-aea ethereum ledger plugin to add support for flashbots." optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "open_aea_ledger_ethereum_flashbots-1.64.0-py3-none-any.whl", hash = "sha256:d0f1e82a63b9aad9c492abf9dd8a8001a3abdf45430c6895e1e129e3e3f94b1c"}, - {file = "open_aea_ledger_ethereum_flashbots-1.64.0.tar.gz", hash = "sha256:63ad60cea5aa8db305e753a9b4df77ba2cdbcb51958f702d4b4c8f41911f7209"}, + {file = "open_aea_ledger_ethereum_flashbots-1.65.0-py3-none-any.whl", hash = "sha256:c52116341b36b7ac99d263161f25b5d38ea815aef611e8a74e306660888baf7b"}, + {file = "open_aea_ledger_ethereum_flashbots-1.65.0.tar.gz", hash = "sha256:2a660f3c5ba4e38fdcd919cd8fd8b03ebea54ba1a08de0896249499e47a6f9a2"}, ] [package.dependencies] open-aea-flashbots = "1.4.0" -open-aea-ledger-ethereum = ">=1.64.0,<1.65.0" +open-aea-ledger-ethereum = ">=1.65.0,<1.66.0" [[package]] name = "open-autonomy" -version = "0.19.4" +version = "0.19.8" description = "A framework for the creation of autonomous agent services." optional = false python-versions = ">=3.8" files = [ - {file = "open_autonomy-0.19.4-py3-none-any.whl", hash = "sha256:c48155be8e0f8e844bcdb78cfc2f231e86f15e2bc853b13a27a545fbc9286ee4"}, - {file = "open_autonomy-0.19.4.tar.gz", hash = "sha256:16ee3ffbb7ba82f076ec2af86e42d063f582b58395b370cd1575522306a93498"}, + {file = "open_autonomy-0.19.8-py3-none-any.whl", hash = "sha256:561802ef6e5ca4487a669bb59c7cc8d395e95561c59e051466169bb896df36fd"}, + {file = "open_autonomy-0.19.8.tar.gz", hash = "sha256:04d1c570c37c6edead57b2f573621d06953ee2f39db91d245e7b59a4e15c039b"}, ] [package.dependencies] @@ -2437,8 +2494,8 @@ Flask = ">=2.0.2,<3.0.0" gql = "3.5.0" hexbytes = "*" jsonschema = ">=4.3.0,<4.4.0" -open-aea = {version = "1.64.0", extras = ["all"]} -open-aea-cli-ipfs = "1.64.0" +open-aea = {version = "1.65.0", extras = ["all"]} +open-aea-cli-ipfs = "1.65.0" protobuf = ">=4.21.6,<4.25.0" pytest = "7.2.1" python-dotenv = ">=0.14.5,<0.22.0" @@ -2451,18 +2508,18 @@ watchdog = ">=2.1.6" werkzeug = "2.0.3" [package.extras] -all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.64.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] -cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.64.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.65.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.65.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] [[package]] name = "orderly-set" -version = "5.3.0" +version = "5.4.1" description = "Orderly set" optional = false python-versions = ">=3.8" files = [ - {file = "orderly_set-5.3.0-py3-none-any.whl", hash = "sha256:c2c0bfe604f5d3d9b24e8262a06feb612594f37aa3845650548befd7772945d1"}, - {file = "orderly_set-5.3.0.tar.gz", hash = "sha256:80b3d8fdd3d39004d9aad389eaa0eab02c71f0a0511ba3a6d54a935a6c6a0acc"}, + {file = "orderly_set-5.4.1-py3-none-any.whl", hash = "sha256:b5e21d21680bd9ef456885db800c5cb4f76a03879880c0175e1b077fb166fd83"}, + {file = "orderly_set-5.4.1.tar.gz", hash = "sha256:a1fb5a4fdc5e234e9e8d8e5c1bbdbc4540f4dfe50d12bf17c8bc5dbf1c9c878d"}, ] [[package]] @@ -2524,124 +2581,124 @@ files = [ [[package]] name = "pluggy" -version = "1.5.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, - {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "propcache" -version = "0.3.0" +version = "0.3.1" description = "Accelerated property cache" optional = false python-versions = ">=3.9" files = [ - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:efa44f64c37cc30c9f05932c740a8b40ce359f51882c70883cc95feac842da4d"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2383a17385d9800b6eb5855c2f05ee550f803878f344f58b6e194de08b96352c"}, - {file = "propcache-0.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3e7420211f5a65a54675fd860ea04173cde60a7cc20ccfbafcccd155225f8bc"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3302c5287e504d23bb0e64d2a921d1eb4a03fb93a0a0aa3b53de059f5a5d737d"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2e068a83552ddf7a39a99488bcba05ac13454fb205c847674da0352602082f"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d913d36bdaf368637b4f88d554fb9cb9d53d6920b9c5563846555938d5450bf"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ee1983728964d6070ab443399c476de93d5d741f71e8f6e7880a065f878e0b9"}, - {file = "propcache-0.3.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:36ca5e9a21822cc1746023e88f5c0af6fce3af3b85d4520efb1ce4221bed75cc"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9ecde3671e62eeb99e977f5221abcf40c208f69b5eb986b061ccec317c82ebd0"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d383bf5e045d7f9d239b38e6acadd7b7fdf6c0087259a84ae3475d18e9a2ae8b"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8cb625bcb5add899cb8ba7bf716ec1d3e8f7cdea9b0713fa99eadf73b6d4986f"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5fa159dcee5dba00c1def3231c249cf261185189205073bde13797e57dd7540a"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:a7080b0159ce05f179cfac592cda1a82898ca9cd097dacf8ea20ae33474fbb25"}, - {file = "propcache-0.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ed7161bccab7696a473fe7ddb619c1d75963732b37da4618ba12e60899fefe4f"}, - {file = "propcache-0.3.0-cp310-cp310-win32.whl", hash = "sha256:bf0d9a171908f32d54f651648c7290397b8792f4303821c42a74e7805bfb813c"}, - {file = "propcache-0.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:42924dc0c9d73e49908e35bbdec87adedd651ea24c53c29cac103ede0ea1d340"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9ddd49258610499aab83b4f5b61b32e11fce873586282a0e972e5ab3bcadee51"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2578541776769b500bada3f8a4eeaf944530516b6e90c089aa368266ed70c49e"}, - {file = "propcache-0.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8074c5dd61c8a3e915fa8fc04754fa55cfa5978200d2daa1e2d4294c1f136aa"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b58229a844931bca61b3a20efd2be2a2acb4ad1622fc026504309a6883686fbf"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e45377d5d6fefe1677da2a2c07b024a6dac782088e37c0b1efea4cfe2b1be19b"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ec5060592d83454e8063e487696ac3783cc48c9a329498bafae0d972bc7816c9"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15010f29fbed80e711db272909a074dc79858c6d28e2915704cfc487a8ac89c6"}, - {file = "propcache-0.3.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a254537b9b696ede293bfdbc0a65200e8e4507bc9f37831e2a0318a9b333c85c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2b975528998de037dfbc10144b8aed9b8dd5a99ec547f14d1cb7c5665a43f075"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:19d36bb351ad5554ff20f2ae75f88ce205b0748c38b146c75628577020351e3c"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6032231d4a5abd67c7f71168fd64a47b6b451fbcb91c8397c2f7610e67683810"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6985a593417cdbc94c7f9c3403747335e450c1599da1647a5af76539672464d3"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a1948df1bb1d56b5e7b0553c0fa04fd0e320997ae99689488201f19fa90d2e7"}, - {file = "propcache-0.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8319293e85feadbbfe2150a5659dbc2ebc4afdeaf7d98936fb9a2f2ba0d4c35c"}, - {file = "propcache-0.3.0-cp311-cp311-win32.whl", hash = "sha256:63f26258a163c34542c24808f03d734b338da66ba91f410a703e505c8485791d"}, - {file = "propcache-0.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:cacea77ef7a2195f04f9279297684955e3d1ae4241092ff0cfcef532bb7a1c32"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e53d19c2bf7d0d1e6998a7e693c7e87300dd971808e6618964621ccd0e01fe4e"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a61a68d630e812b67b5bf097ab84e2cd79b48c792857dc10ba8a223f5b06a2af"}, - {file = "propcache-0.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fb91d20fa2d3b13deea98a690534697742029f4fb83673a3501ae6e3746508b5"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67054e47c01b7b349b94ed0840ccae075449503cf1fdd0a1fdd98ab5ddc2667b"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997e7b8f173a391987df40f3b52c423e5850be6f6df0dcfb5376365440b56667"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d663fd71491dde7dfdfc899d13a067a94198e90695b4321084c6e450743b8c7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8884ba1a0fe7210b775106b25850f5e5a9dc3c840d1ae9924ee6ea2eb3acbfe7"}, - {file = "propcache-0.3.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa806bbc13eac1ab6291ed21ecd2dd426063ca5417dd507e6be58de20e58dfcf"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6f4d7a7c0aff92e8354cceca6fe223973ddf08401047920df0fcb24be2bd5138"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:9be90eebc9842a93ef8335291f57b3b7488ac24f70df96a6034a13cb58e6ff86"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:bf15fc0b45914d9d1b706f7c9c4f66f2b7b053e9517e40123e137e8ca8958b3d"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5a16167118677d94bb48bfcd91e420088854eb0737b76ec374b91498fb77a70e"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:41de3da5458edd5678b0f6ff66691507f9885f5fe6a0fb99a5d10d10c0fd2d64"}, - {file = "propcache-0.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:728af36011bb5d344c4fe4af79cfe186729efb649d2f8b395d1572fb088a996c"}, - {file = "propcache-0.3.0-cp312-cp312-win32.whl", hash = "sha256:6b5b7fd6ee7b54e01759f2044f936dcf7dea6e7585f35490f7ca0420fe723c0d"}, - {file = "propcache-0.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:2d15bc27163cd4df433e75f546b9ac31c1ba7b0b128bfb1b90df19082466ff57"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a2b9bf8c79b660d0ca1ad95e587818c30ccdb11f787657458d6f26a1ea18c568"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b0c1a133d42c6fc1f5fbcf5c91331657a1ff822e87989bf4a6e2e39b818d0ee9"}, - {file = "propcache-0.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bb2f144c6d98bb5cbc94adeb0447cfd4c0f991341baa68eee3f3b0c9c0e83767"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1323cd04d6e92150bcc79d0174ce347ed4b349d748b9358fd2e497b121e03c8"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b812b3cb6caacd072276ac0492d249f210006c57726b6484a1e1805b3cfeea0"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:742840d1d0438eb7ea4280f3347598f507a199a35a08294afdcc560c3739989d"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c6e7e4f9167fddc438cd653d826f2222222564daed4116a02a184b464d3ef05"}, - {file = "propcache-0.3.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a94ffc66738da99232ddffcf7910e0f69e2bbe3a0802e54426dbf0714e1c2ffe"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c6ec957025bf32b15cbc6b67afe233c65b30005e4c55fe5768e4bb518d712f1"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:549722908de62aa0b47a78b90531c022fa6e139f9166be634f667ff45632cc92"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5d62c4f6706bff5d8a52fd51fec6069bef69e7202ed481486c0bc3874912c787"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:24c04f8fbf60094c531667b8207acbae54146661657a1b1be6d3ca7773b7a545"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7c5f5290799a3f6539cc5e6f474c3e5c5fbeba74a5e1e5be75587746a940d51e"}, - {file = "propcache-0.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4fa0e7c9c3cf7c276d4f6ab9af8adddc127d04e0fcabede315904d2ff76db626"}, - {file = "propcache-0.3.0-cp313-cp313-win32.whl", hash = "sha256:ee0bd3a7b2e184e88d25c9baa6a9dc609ba25b76daae942edfb14499ac7ec374"}, - {file = "propcache-0.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:1c8f7d896a16da9455f882870a507567d4f58c53504dc2d4b1e1d386dfe4588a"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e560fd75aaf3e5693b91bcaddd8b314f4d57e99aef8a6c6dc692f935cc1e6bbf"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65a37714b8ad9aba5780325228598a5b16c47ba0f8aeb3dc0514701e4413d7c0"}, - {file = "propcache-0.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:07700939b2cbd67bfb3b76a12e1412405d71019df00ca5697ce75e5ef789d829"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c0fdbdf6983526e269e5a8d53b7ae3622dd6998468821d660d0daf72779aefa"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:794c3dd744fad478b6232289c866c25406ecdfc47e294618bdf1697e69bd64a6"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4544699674faf66fb6b4473a1518ae4999c1b614f0b8297b1cef96bac25381db"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fddb8870bdb83456a489ab67c6b3040a8d5a55069aa6f72f9d872235fbc52f54"}, - {file = "propcache-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f857034dc68d5ceb30fb60afb6ff2103087aea10a01b613985610e007053a121"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:02df07041e0820cacc8f739510078f2aadcfd3fc57eaeeb16d5ded85c872c89e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f47d52fd9b2ac418c4890aad2f6d21a6b96183c98021f0a48497a904199f006e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:9ff4e9ecb6e4b363430edf2c6e50173a63e0820e549918adef70515f87ced19a"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:ecc2920630283e0783c22e2ac94427f8cca29a04cfdf331467d4f661f4072dac"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:c441c841e82c5ba7a85ad25986014be8d7849c3cfbdb6004541873505929a74e"}, - {file = "propcache-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6c929916cbdb540d3407c66f19f73387f43e7c12fa318a66f64ac99da601bcdf"}, - {file = "propcache-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:0c3e893c4464ebd751b44ae76c12c5f5c1e4f6cbd6fbf67e3783cd93ad221863"}, - {file = "propcache-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:75e872573220d1ee2305b35c9813626e620768248425f58798413e9c39741f46"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:03c091bb752349402f23ee43bb2bff6bd80ccab7c9df6b88ad4322258d6960fc"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46ed02532cb66612d42ae5c3929b5e98ae330ea0f3900bc66ec5f4862069519b"}, - {file = "propcache-0.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11ae6a8a01b8a4dc79093b5d3ca2c8a4436f5ee251a9840d7790dccbd96cb649"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df03cd88f95b1b99052b52b1bb92173229d7a674df0ab06d2b25765ee8404bce"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03acd9ff19021bd0567582ac88f821b66883e158274183b9e5586f678984f8fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd54895e4ae7d32f1e3dd91261df46ee7483a735017dc6f987904f194aa5fd14"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26a67e5c04e3119594d8cfae517f4b9330c395df07ea65eab16f3d559b7068fe"}, - {file = "propcache-0.3.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee25f1ac091def37c4b59d192bbe3a206298feeb89132a470325bf76ad122a1e"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:58e6d2a5a7cb3e5f166fd58e71e9a4ff504be9dc61b88167e75f835da5764d07"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:be90c94570840939fecedf99fa72839aed70b0ced449b415c85e01ae67422c90"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:49ea05212a529c2caffe411e25a59308b07d6e10bf2505d77da72891f9a05641"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:119e244ab40f70a98c91906d4c1f4c5f2e68bd0b14e7ab0a06922038fae8a20f"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:507c5357a8d8b4593b97fb669c50598f4e6cccbbf77e22fa9598aba78292b4d7"}, - {file = "propcache-0.3.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8526b0941ec5a40220fc4dfde76aed58808e2b309c03e9fa8e2260083ef7157f"}, - {file = "propcache-0.3.0-cp39-cp39-win32.whl", hash = "sha256:7cedd25e5f678f7738da38037435b340694ab34d424938041aa630d8bac42663"}, - {file = "propcache-0.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:bf4298f366ca7e1ad1d21bbb58300a6985015909964077afd37559084590c929"}, - {file = "propcache-0.3.0-py3-none-any.whl", hash = "sha256:67dda3c7325691c2081510e92c561f465ba61b975f481735aefdfc845d2cd043"}, - {file = "propcache-0.3.0.tar.gz", hash = "sha256:a8fd93de4e1d278046345f49e2238cdb298589325849b2645d4a94c53faeffc5"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f27785888d2fdd918bc36de8b8739f2d6c791399552333721b58193f68ea3e98"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4e89cde74154c7b5957f87a355bb9c8ec929c167b59c83d90654ea36aeb6180"}, + {file = "propcache-0.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:730178f476ef03d3d4d255f0c9fa186cb1d13fd33ffe89d39f2cda4da90ceb71"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967a8eec513dbe08330f10137eacb427b2ca52118769e82ebcfcab0fba92a649"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b9145c35cc87313b5fd480144f8078716007656093d23059e8993d3a8fa730f"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9e64e948ab41411958670f1093c0a57acfdc3bee5cf5b935671bbd5313bcf229"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:319fa8765bfd6a265e5fa661547556da381e53274bc05094fc9ea50da51bfd46"}, + {file = "propcache-0.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66d8ccbc902ad548312b96ed8d5d266d0d2c6d006fd0f66323e9d8f2dd49be7"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2d219b0dbabe75e15e581fc1ae796109b07c8ba7d25b9ae8d650da582bed01b0"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:cd6a55f65241c551eb53f8cf4d2f4af33512c39da5d9777694e9d9c60872f519"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9979643ffc69b799d50d3a7b72b5164a2e97e117009d7af6dfdd2ab906cb72cd"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4cf9e93a81979f1424f1a3d155213dc928f1069d697e4353edb8a5eba67c6259"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2fce1df66915909ff6c824bbb5eb403d2d15f98f1518e583074671a30fe0c21e"}, + {file = "propcache-0.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4d0dfdd9a2ebc77b869a0b04423591ea8823f791293b527dc1bb896c1d6f1136"}, + {file = "propcache-0.3.1-cp310-cp310-win32.whl", hash = "sha256:1f6cc0ad7b4560e5637eb2c994e97b4fa41ba8226069c9277eb5ea7101845b42"}, + {file = "propcache-0.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:47ef24aa6511e388e9894ec16f0fbf3313a53ee68402bc428744a367ec55b833"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7f30241577d2fef2602113b70ef7231bf4c69a97e04693bde08ddab913ba0ce5"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:43593c6772aa12abc3af7784bff4a41ffa921608dd38b77cf1dfd7f5c4e71371"}, + {file = "propcache-0.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a75801768bbe65499495660b777e018cbe90c7980f07f8aa57d6be79ea6f71da"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6f1324db48f001c2ca26a25fa25af60711e09b9aaf4b28488602776f4f9a744"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cdb0f3e1eb6dfc9965d19734d8f9c481b294b5274337a8cb5cb01b462dcb7e0"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1eb34d90aac9bfbced9a58b266f8946cb5935869ff01b164573a7634d39fbcb5"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35c7070eeec2cdaac6fd3fe245226ed2a6292d3ee8c938e5bb645b434c5f256"}, + {file = "propcache-0.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b23c11c2c9e6d4e7300c92e022046ad09b91fd00e36e83c44483df4afa990073"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3e19ea4ea0bf46179f8a3652ac1426e6dcbaf577ce4b4f65be581e237340420d"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:bd39c92e4c8f6cbf5f08257d6360123af72af9f4da75a690bef50da77362d25f"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0313e8b923b3814d1c4a524c93dfecea5f39fa95601f6a9b1ac96cd66f89ea0"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e861ad82892408487be144906a368ddbe2dc6297074ade2d892341b35c59844a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:61014615c1274df8da5991a1e5da85a3ccb00c2d4701ac6f3383afd3ca47ab0a"}, + {file = "propcache-0.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:71ebe3fe42656a2328ab08933d420df5f3ab121772eef78f2dc63624157f0ed9"}, + {file = "propcache-0.3.1-cp311-cp311-win32.whl", hash = "sha256:58aa11f4ca8b60113d4b8e32d37e7e78bd8af4d1a5b5cb4979ed856a45e62005"}, + {file = "propcache-0.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:9532ea0b26a401264b1365146c440a6d78269ed41f83f23818d4b79497aeabe7"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f78eb8422acc93d7b69964012ad7048764bb45a54ba7a39bb9e146c72ea29723"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:89498dd49c2f9a026ee057965cdf8192e5ae070ce7d7a7bd4b66a8e257d0c976"}, + {file = "propcache-0.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09400e98545c998d57d10035ff623266927cb784d13dd2b31fd33b8a5316b85b"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8efd8c5adc5a2c9d3b952815ff8f7710cefdcaf5f2c36d26aff51aeca2f12f"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2fe5c910f6007e716a06d269608d307b4f36e7babee5f36533722660e8c4a70"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0ab8cf8cdd2194f8ff979a43ab43049b1df0b37aa64ab7eca04ac14429baeb7"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:563f9d8c03ad645597b8d010ef4e9eab359faeb11a0a2ac9f7b4bc8c28ebef25"}, + {file = "propcache-0.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6e0faf8cb6b4beea5d6ed7b5a578254c6d7df54c36ccd3d8b3eb00d6770277"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1c5c7ab7f2bb3f573d1cb921993006ba2d39e8621019dffb1c5bc94cdbae81e8"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:050b571b2e96ec942898f8eb46ea4bfbb19bd5502424747e83badc2d4a99a44e"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e1c4d24b804b3a87e9350f79e2371a705a188d292fd310e663483af6ee6718ee"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e4fe2a6d5ce975c117a6bb1e8ccda772d1e7029c1cca1acd209f91d30fa72815"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:feccd282de1f6322f56f6845bf1207a537227812f0a9bf5571df52bb418d79d5"}, + {file = "propcache-0.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ec314cde7314d2dd0510c6787326bbffcbdc317ecee6b7401ce218b3099075a7"}, + {file = "propcache-0.3.1-cp312-cp312-win32.whl", hash = "sha256:7d2d5a0028d920738372630870e7d9644ce437142197f8c827194fca404bf03b"}, + {file = "propcache-0.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:88c423efef9d7a59dae0614eaed718449c09a5ac79a5f224a8b9664d603f04a3"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f1528ec4374617a7a753f90f20e2f551121bb558fcb35926f99e3c42367164b8"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dc1915ec523b3b494933b5424980831b636fe483d7d543f7afb7b3bf00f0c10f"}, + {file = "propcache-0.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a110205022d077da24e60b3df8bcee73971be9575dec5573dd17ae5d81751111"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d249609e547c04d190e820d0d4c8ca03ed4582bcf8e4e160a6969ddfb57b62e5"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ced33d827625d0a589e831126ccb4f5c29dfdf6766cac441d23995a65825dcb"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4114c4ada8f3181af20808bedb250da6bae56660e4b8dfd9cd95d4549c0962f7"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:975af16f406ce48f1333ec5e912fe11064605d5c5b3f6746969077cc3adeb120"}, + {file = "propcache-0.3.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a34aa3a1abc50740be6ac0ab9d594e274f59960d3ad253cd318af76b996dd654"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9cec3239c85ed15bfaded997773fdad9fb5662b0a7cbc854a43f291eb183179e"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:05543250deac8e61084234d5fc54f8ebd254e8f2b39a16b1dce48904f45b744b"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5cb5918253912e088edbf023788de539219718d3b10aef334476b62d2b53de53"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f3bbecd2f34d0e6d3c543fdb3b15d6b60dd69970c2b4c822379e5ec8f6f621d5"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aca63103895c7d960a5b9b044a83f544b233c95e0dcff114389d64d762017af7"}, + {file = "propcache-0.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5a0a9898fdb99bf11786265468571e628ba60af80dc3f6eb89a3545540c6b0ef"}, + {file = "propcache-0.3.1-cp313-cp313-win32.whl", hash = "sha256:3a02a28095b5e63128bcae98eb59025924f121f048a62393db682f049bf4ac24"}, + {file = "propcache-0.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:813fbb8b6aea2fc9659815e585e548fe706d6f663fa73dff59a1677d4595a037"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a444192f20f5ce8a5e52761a031b90f5ea6288b1eef42ad4c7e64fef33540b8f"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0fbe94666e62ebe36cd652f5fc012abfbc2342de99b523f8267a678e4dfdee3c"}, + {file = "propcache-0.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f011f104db880f4e2166bcdcf7f58250f7a465bc6b068dc84c824a3d4a5c94dc"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e584b6d388aeb0001d6d5c2bd86b26304adde6d9bb9bfa9c4889805021b96de"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a17583515a04358b034e241f952f1715243482fc2c2945fd99a1b03a0bd77d6"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5aed8d8308215089c0734a2af4f2e95eeb360660184ad3912686c181e500b2e7"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d8e309ff9a0503ef70dc9a0ebd3e69cf7b3894c9ae2ae81fc10943c37762458"}, + {file = "propcache-0.3.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b655032b202028a582d27aeedc2e813299f82cb232f969f87a4fde491a233f11"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9f64d91b751df77931336b5ff7bafbe8845c5770b06630e27acd5dbb71e1931c"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:19a06db789a4bd896ee91ebc50d059e23b3639c25d58eb35be3ca1cbe967c3bf"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:bef100c88d8692864651b5f98e871fb090bd65c8a41a1cb0ff2322db39c96c27"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:87380fb1f3089d2a0b8b00f006ed12bd41bd858fabfa7330c954c70f50ed8757"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e474fc718e73ba5ec5180358aa07f6aded0ff5f2abe700e3115c37d75c947e18"}, + {file = "propcache-0.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:17d1c688a443355234f3c031349da69444be052613483f3e4158eef751abcd8a"}, + {file = "propcache-0.3.1-cp313-cp313t-win32.whl", hash = "sha256:359e81a949a7619802eb601d66d37072b79b79c2505e6d3fd8b945538411400d"}, + {file = "propcache-0.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e7fb9a84c9abbf2b2683fa3e7b0d7da4d8ecf139a1c635732a8bda29c5214b0e"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ed5f6d2edbf349bd8d630e81f474d33d6ae5d07760c44d33cd808e2f5c8f4ae6"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:668ddddc9f3075af019f784456267eb504cb77c2c4bd46cc8402d723b4d200bf"}, + {file = "propcache-0.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c86e7ceea56376216eba345aa1fc6a8a6b27ac236181f840d1d7e6a1ea9ba5c"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83be47aa4e35b87c106fc0c84c0fc069d3f9b9b06d3c494cd404ec6747544894"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:27c6ac6aa9fc7bc662f594ef380707494cb42c22786a558d95fcdedb9aa5d035"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a956dff37080b352c1c40b2966b09defb014347043e740d420ca1eb7c9b908"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82de5da8c8893056603ac2d6a89eb8b4df49abf1a7c19d536984c8dd63f481d5"}, + {file = "propcache-0.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c3c3a203c375b08fd06a20da3cf7aac293b834b6f4f4db71190e8422750cca5"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b303b194c2e6f171cfddf8b8ba30baefccf03d36a4d9cab7fd0bb68ba476a3d7"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:916cd229b0150129d645ec51614d38129ee74c03293a9f3f17537be0029a9641"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a461959ead5b38e2581998700b26346b78cd98540b5524796c175722f18b0294"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:069e7212890b0bcf9b2be0a03afb0c2d5161d91e1bf51569a64f629acc7defbf"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ef2e4e91fb3945769e14ce82ed53007195e616a63aa43b40fb7ebaaf907c8d4c"}, + {file = "propcache-0.3.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8638f99dca15b9dff328fb6273e09f03d1c50d9b6512f3b65a4154588a7595fe"}, + {file = "propcache-0.3.1-cp39-cp39-win32.whl", hash = "sha256:6f173bbfe976105aaa890b712d1759de339d8a7cef2fc0a1714cc1a1e1c47f64"}, + {file = "propcache-0.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:603f1fe4144420374f1a69b907494c3acbc867a581c2d49d4175b0de7cc64566"}, + {file = "propcache-0.3.1-py3-none-any.whl", hash = "sha256:9a8ecf38de50a7f518c21568c80f985e776397b902f1ce0b01f799aba1608b40"}, + {file = "propcache-0.3.1.tar.gz", hash = "sha256:40d980c33765359098837527e18eddefc9a24cea5b45e078a7f3bb5b032c6ecf"}, ] [[package]] @@ -2739,60 +2796,70 @@ files = [ [[package]] name = "pycryptodome" -version = "3.21.0" +version = "3.23.0" description = "Cryptographic library for Python" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" -files = [ - {file = "pycryptodome-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ba4cc304eac4d4d458f508d4955a88ba25026890e8abff9b60404f76a62c55e"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb087b8612c8a1a14cf37dd754685be9a8d9869bed2ffaaceb04850a8aeef7e"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:26412b21df30b2861424a6c6d5b1d8ca8107612a4cfa4d0183e71c5d200fb34a"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-win32.whl", hash = "sha256:cc2269ab4bce40b027b49663d61d816903a4bd90ad88cb99ed561aadb3888dd3"}, - {file = "pycryptodome-3.21.0-cp27-cp27m-win_amd64.whl", hash = "sha256:0fa0a05a6a697ccbf2a12cec3d6d2650b50881899b845fac6e87416f8cb7e87d"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6cce52e196a5f1d6797ff7946cdff2038d3b5f0aba4a43cb6bf46b575fd1b5bb"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a915597ffccabe902e7090e199a7bf7a381c5506a747d5e9d27ba55197a2c568"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e74c522d630766b03a836c15bff77cb657c5fdf098abf8b1ada2aebc7d0819"}, - {file = "pycryptodome-3.21.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:a3804675283f4764a02db05f5191eb8fec2bb6ca34d466167fc78a5f05bbe6b3"}, - {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4"}, - {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8"}, - {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2"}, - {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93"}, - {file = "pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764"}, - {file = "pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53"}, - {file = "pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca"}, - {file = "pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0"}, - {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:590ef0898a4b0a15485b05210b4a1c9de8806d3ad3d47f74ab1dc07c67a6827f"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58"}, - {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8acd7d34af70ee63f9a849f957558e49a98f8f1634f86a59d2be62bb8e93f71c"}, - {file = "pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297"}, +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "pycryptodome-3.23.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a176b79c49af27d7f6c12e4b178b0824626f40a7b9fed08f712291b6d54bf566"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:573a0b3017e06f2cffd27d92ef22e46aa3be87a2d317a5abf7cc0e84e321bd75"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:63dad881b99ca653302b2c7191998dd677226222a3f2ea79999aa51ce695f720"}, + {file = "pycryptodome-3.23.0-cp27-cp27m-win32.whl", hash = "sha256:b34e8e11d97889df57166eda1e1ddd7676da5fcd4d71a0062a760e75060514b4"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:7ac1080a8da569bde76c0a104589c4f414b8ba296c0b3738cf39a466a9fb1818"}, + {file = "pycryptodome-3.23.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:6fe8258e2039eceb74dfec66b3672552b6b7d2c235b2dfecc05d16b8921649a8"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625"}, + {file = "pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27"}, + {file = "pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575"}, + {file = "pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f"}, + {file = "pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2"}, + {file = "pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56"}, + {file = "pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353"}, + {file = "pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:865d83c906b0fc6a59b510deceee656b6bc1c4fa0d82176e2b77e97a420a996a"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89d4d56153efc4d81defe8b65fd0821ef8b2d5ddf8ed19df31ba2f00872b8002"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3f2d0aaf8080bda0587d58fc9fe4766e012441e2eed4269a77de6aea981c8be"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:64093fc334c1eccfd3933c134c4457c34eaca235eeae49d69449dc4728079339"}, + {file = "pycryptodome-3.23.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ce64e84a962b63a47a592690bdc16a7eaf709d2c2697ababf24a0def566899a6"}, + {file = "pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef"}, ] [[package]] name = "pydantic" -version = "2.10.6" +version = "2.11.4" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"}, - {file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"}, + {file = "pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb"}, + {file = "pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d"}, ] [package.dependencies] annotated-types = ">=0.6.0" -pydantic-core = "2.27.2" +pydantic-core = "2.33.2" typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" [package.extras] email = ["email-validator (>=2.0.0)"] @@ -2800,111 +2867,110 @@ timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.27.2" +version = "2.33.2" description = "Core functionality for Pydantic validation and serialization" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"}, - {file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a"}, - {file = "pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9"}, - {file = "pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af"}, - {file = "pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4"}, - {file = "pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31"}, - {file = "pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc"}, - {file = "pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048"}, - {file = "pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474"}, - {file = "pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc"}, - {file = "pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0"}, - {file = "pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2"}, - {file = "pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4"}, - {file = "pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9"}, - {file = "pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b"}, - {file = "pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b"}, - {file = "pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e"}, - {file = "pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee"}, - {file = "pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee"}, - {file = "pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b"}, - {file = "pydantic_core-2.27.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506"}, - {file = "pydantic_core-2.27.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5"}, - {file = "pydantic_core-2.27.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9"}, - {file = "pydantic_core-2.27.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da"}, - {file = "pydantic_core-2.27.2-cp38-cp38-win32.whl", hash = "sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b"}, - {file = "pydantic_core-2.27.2-cp38-cp38-win_amd64.whl", hash = "sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad"}, - {file = "pydantic_core-2.27.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993"}, - {file = "pydantic_core-2.27.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630"}, - {file = "pydantic_core-2.27.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362"}, - {file = "pydantic_core-2.27.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96"}, - {file = "pydantic_core-2.27.2-cp39-cp39-win32.whl", hash = "sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e"}, - {file = "pydantic_core-2.27.2-cp39-cp39-win_amd64.whl", hash = "sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9"}, - {file = "pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2"}, - {file = "pydantic_core-2.27.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35"}, - {file = "pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, + {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, ] [package.dependencies] @@ -2912,32 +2978,32 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pyinstaller" -version = "6.12.0" +version = "6.13.0" description = "PyInstaller bundles a Python application and all its dependencies into a single package." optional = false python-versions = "<3.14,>=3.8" files = [ - {file = "pyinstaller-6.12.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:68f1e4cecf88a6272063977fa2a2c69ad37cf568e5901769d7206d0314c74f47"}, - {file = "pyinstaller-6.12.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:fea76fc9b55ffa730fcf90beb897cce4399938460b0b6f40507fbebfc752c753"}, - {file = "pyinstaller-6.12.0-py3-none-manylinux2014_i686.whl", hash = "sha256:dac8a27988dbc33cdc34f2046803258bc3f6829de24de52745a5daa22bdba0f1"}, - {file = "pyinstaller-6.12.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:83c7f3bde9871b4a6aa71c66a96e8ba5c21668ce711ed97f510b9382d10aac6c"}, - {file = "pyinstaller-6.12.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:a69818815c6e0711c727edc30680cb1f81c691b59de35db81a2d9e0ae26a9ef1"}, - {file = "pyinstaller-6.12.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:a2abf5fde31a8b38b6df7939bcef8ac1d0c51e97e25317ce3555cd675259750f"}, - {file = "pyinstaller-6.12.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:8e92e9873a616547bbabbb5a3a9843d5f2ab40c3d8b26810acdf0fe257bee4cf"}, - {file = "pyinstaller-6.12.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:aefe502d55c9cf6aeaed7feba80b5f8491ce43f8f2b5fe2d9aadca3ee5a05bc4"}, - {file = "pyinstaller-6.12.0-py3-none-win32.whl", hash = "sha256:138856a5a503bb69c066377e0a22671b0db063e9cc14d5cf5c798a53561200d3"}, - {file = "pyinstaller-6.12.0-py3-none-win_amd64.whl", hash = "sha256:0e62d3906309248409f215b386f33afec845214e69cc0f296b93222b26a88f43"}, - {file = "pyinstaller-6.12.0-py3-none-win_arm64.whl", hash = "sha256:0c271896a3a168f4f91827145702543db9c5427f4c7372a6df8c75925a3ac18a"}, - {file = "pyinstaller-6.12.0.tar.gz", hash = "sha256:1834797be48ce1b26015af68bdeb3c61a6c7500136f04e0fc65e468115dec777"}, + {file = "pyinstaller-6.13.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:aa404f0b02cd57948098055e76ee190b8e65ccf7a2a3f048e5000f668317069f"}, + {file = "pyinstaller-6.13.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:92efcf2f09e78f07b568c5cb7ed48c9940f5dad627af4b49bede6320fab2a06e"}, + {file = "pyinstaller-6.13.0-py3-none-manylinux2014_i686.whl", hash = "sha256:9f82f113c463f012faa0e323d952ca30a6f922685d9636e754bd3a256c7ed200"}, + {file = "pyinstaller-6.13.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:db0e7945ebe276f604eb7c36e536479556ab32853412095e19172a5ec8fca1c5"}, + {file = "pyinstaller-6.13.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:92fe7337c5aa08d42b38d7a79614492cb571489f2cb0a8f91dc9ef9ccbe01ed3"}, + {file = "pyinstaller-6.13.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:bc09795f5954135dd4486c1535650958c8218acb954f43860e4b05fb515a21c0"}, + {file = "pyinstaller-6.13.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:589937548d34978c568cfdc39f31cf386f45202bc27fdb8facb989c79dfb4c02"}, + {file = "pyinstaller-6.13.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:b7260832f7501ba1d2ce1834d4cddc0f2b94315282bc89c59333433715015447"}, + {file = "pyinstaller-6.13.0-py3-none-win32.whl", hash = "sha256:80c568848529635aa7ca46d8d525f68486d53e03f68b7bb5eba2c88d742e302c"}, + {file = "pyinstaller-6.13.0-py3-none-win_amd64.whl", hash = "sha256:8d4296236b85aae570379488c2da833b28828b17c57c2cc21fccd7e3811fe372"}, + {file = "pyinstaller-6.13.0-py3-none-win_arm64.whl", hash = "sha256:d9f21d56ca2443aa6a1e255e7ad285c76453893a454105abe1b4d45e92bb9a20"}, + {file = "pyinstaller-6.13.0.tar.gz", hash = "sha256:38911feec2c5e215e5159a7e66fdb12400168bd116143b54a8a7a37f08733456"}, ] [package.dependencies] altgraph = "*" -importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} +importlib_metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} packaging = ">=22.0" pefile = {version = ">=2022.5.30,<2024.8.26 || >2024.8.26", markers = "sys_platform == \"win32\""} -pyinstaller-hooks-contrib = ">=2025.1" +pyinstaller-hooks-contrib = ">=2025.2" pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""} setuptools = ">=42.0.0" @@ -2947,13 +3013,13 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2025.1" +version = "2025.4" description = "Community maintained hooks for PyInstaller" optional = false python-versions = ">=3.8" files = [ - {file = "pyinstaller_hooks_contrib-2025.1-py3-none-any.whl", hash = "sha256:d3c799470cbc0bda60dcc8e6b4ab976777532b77621337f2037f558905e3a8e9"}, - {file = "pyinstaller_hooks_contrib-2025.1.tar.gz", hash = "sha256:130818f9e9a0a7f2261f1fd66054966a3a50c99d000981c5d1db11d3ad0c6ab2"}, + {file = "pyinstaller_hooks_contrib-2025.4-py3-none-any.whl", hash = "sha256:6c2d73269b4c484eb40051fc1acee0beb113c2cfb3b37437b8394faae6f0d072"}, + {file = "pyinstaller_hooks_contrib-2025.4.tar.gz", hash = "sha256:5ce1afd1997b03e70f546207031cfdf2782030aabacc102190677059e2856446"}, ] [package.dependencies] @@ -3120,27 +3186,27 @@ cli = ["click (>=5.0)"] [[package]] name = "pywin32" -version = "309" +version = "310" description = "Python for Window Extensions" optional = false python-versions = "*" files = [ - {file = "pywin32-309-cp310-cp310-win32.whl", hash = "sha256:5b78d98550ca093a6fe7ab6d71733fbc886e2af9d4876d935e7f6e1cd6577ac9"}, - {file = "pywin32-309-cp310-cp310-win_amd64.whl", hash = "sha256:728d08046f3d65b90d4c77f71b6fbb551699e2005cc31bbffd1febd6a08aa698"}, - {file = "pywin32-309-cp310-cp310-win_arm64.whl", hash = "sha256:c667bcc0a1e6acaca8984eb3e2b6e42696fc035015f99ff8bc6c3db4c09a466a"}, - {file = "pywin32-309-cp311-cp311-win32.whl", hash = "sha256:d5df6faa32b868baf9ade7c9b25337fa5eced28eb1ab89082c8dae9c48e4cd51"}, - {file = "pywin32-309-cp311-cp311-win_amd64.whl", hash = "sha256:e7ec2cef6df0926f8a89fd64959eba591a1eeaf0258082065f7bdbe2121228db"}, - {file = "pywin32-309-cp311-cp311-win_arm64.whl", hash = "sha256:54ee296f6d11db1627216e9b4d4c3231856ed2d9f194c82f26c6cb5650163f4c"}, - {file = "pywin32-309-cp312-cp312-win32.whl", hash = "sha256:de9acacced5fa82f557298b1fed5fef7bd49beee04190f68e1e4783fbdc19926"}, - {file = "pywin32-309-cp312-cp312-win_amd64.whl", hash = "sha256:6ff9eebb77ffc3d59812c68db33c0a7817e1337e3537859499bd27586330fc9e"}, - {file = "pywin32-309-cp312-cp312-win_arm64.whl", hash = "sha256:619f3e0a327b5418d833f44dc87859523635cf339f86071cc65a13c07be3110f"}, - {file = "pywin32-309-cp313-cp313-win32.whl", hash = "sha256:008bffd4afd6de8ca46c6486085414cc898263a21a63c7f860d54c9d02b45c8d"}, - {file = "pywin32-309-cp313-cp313-win_amd64.whl", hash = "sha256:bd0724f58492db4cbfbeb1fcd606495205aa119370c0ddc4f70e5771a3ab768d"}, - {file = "pywin32-309-cp313-cp313-win_arm64.whl", hash = "sha256:8fd9669cfd41863b688a1bc9b1d4d2d76fd4ba2128be50a70b0ea66b8d37953b"}, - {file = "pywin32-309-cp38-cp38-win32.whl", hash = "sha256:617b837dc5d9dfa7e156dbfa7d3906c009a2881849a80a9ae7519f3dd8c6cb86"}, - {file = "pywin32-309-cp38-cp38-win_amd64.whl", hash = "sha256:0be3071f555480fbfd86a816a1a773880ee655bf186aa2931860dbb44e8424f8"}, - {file = "pywin32-309-cp39-cp39-win32.whl", hash = "sha256:72ae9ae3a7a6473223589a1621f9001fe802d59ed227fd6a8503c9af67c1d5f4"}, - {file = "pywin32-309-cp39-cp39-win_amd64.whl", hash = "sha256:88bc06d6a9feac70783de64089324568ecbc65866e2ab318eab35da3811fd7ef"}, + {file = "pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1"}, + {file = "pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d"}, + {file = "pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213"}, + {file = "pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd"}, + {file = "pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c"}, + {file = "pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582"}, + {file = "pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d"}, + {file = "pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060"}, + {file = "pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966"}, + {file = "pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab"}, + {file = "pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e"}, + {file = "pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33"}, + {file = "pywin32-310-cp38-cp38-win32.whl", hash = "sha256:0867beb8addefa2e3979d4084352e4ac6e991ca45373390775f7084cc0209b9c"}, + {file = "pywin32-310-cp38-cp38-win_amd64.whl", hash = "sha256:30f0a9b3138fb5e07eb4973b7077e1883f558e40c578c6925acc7a94c34eaa36"}, + {file = "pywin32-310-cp39-cp39-win32.whl", hash = "sha256:851c8d927af0d879221e616ae1f66145253537bbdd321a77e8ef701b443a9a1a"}, + {file = "pywin32-310-cp39-cp39-win_amd64.whl", hash = "sha256:96867217335559ac619f00ad70e513c0fcf84b8a3af9fc2bba3b59b97da70475"}, ] [[package]] @@ -3386,18 +3452,18 @@ files = [ [[package]] name = "setuptools" -version = "76.0.0" +version = "80.8.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.9" files = [ - {file = "setuptools-76.0.0-py3-none-any.whl", hash = "sha256:199466a166ff664970d0ee145839f5582cb9bca7a0a3a2e795b6a9cb2308e9c6"}, - {file = "setuptools-76.0.0.tar.gz", hash = "sha256:43b4ee60e10b0d0ee98ad11918e114c70701bc6051662a9a675a0496c1a158f4"}, + {file = "setuptools-80.8.0-py3-none-any.whl", hash = "sha256:95a60484590d24103af13b686121328cc2736bee85de8936383111e421b9edc0"}, + {file = "setuptools-80.8.0.tar.gz", hash = "sha256:49f7af965996f26d43c8ae34539c8d99c5042fbff34302ea151eaa9c207cd257"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.8.0)"] -core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +core = ["importlib_metadata (>=6)", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] @@ -3439,13 +3505,13 @@ files = [ [[package]] name = "soupsieve" -version = "2.6" +version = "2.7" description = "A modern CSS selector implementation for Beautiful Soup." optional = false python-versions = ">=3.8" files = [ - {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, - {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, + {file = "soupsieve-2.7-py3-none-any.whl", hash = "sha256:6e60cc5c1ffaf1cebcc12e8188320b72071e922c2e897f737cadce79ad5d30c4"}, + {file = "soupsieve-2.7.tar.gz", hash = "sha256:ad282f9b6926286d2ead4750552c8a6142bc4c783fd66b0293547c8fe6ae126a"}, ] [[package]] @@ -3479,13 +3545,13 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "termcolor" -version = "2.5.0" +version = "3.1.0" description = "ANSI color formatting for output in terminal" optional = false python-versions = ">=3.9" files = [ - {file = "termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8"}, - {file = "termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f"}, + {file = "termcolor-3.1.0-py3-none-any.whl", hash = "sha256:591dd26b5c2ce03b9e43f391264626557873ce1d379019786f99b0c2bee140aa"}, + {file = "termcolor-3.1.0.tar.gz", hash = "sha256:6a6dd7fbee581909eeec6a756cff1d7f7c376063b14e4a298dc4980309e55970"}, ] [package.extras] @@ -3574,24 +3640,38 @@ pyotp = "*" [[package]] name = "typing-extensions" -version = "4.12.2" +version = "4.13.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, - {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, + {file = "typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c"}, + {file = "typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +files = [ + {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, + {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, ] +[package.dependencies] +typing-extensions = ">=4.12.0" + [[package]] name = "urllib3" -version = "2.3.0" +version = "2.4.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.9" files = [ - {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, - {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, + {file = "urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813"}, + {file = "urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466"}, ] [package.extras] @@ -3840,99 +3920,121 @@ watchdog = ["watchdog"] [[package]] name = "yarl" -version = "1.18.3" +version = "1.20.0" description = "Yet another URL library" optional = false python-versions = ">=3.9" files = [ - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"}, - {file = "yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc"}, - {file = "yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b"}, - {file = "yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690"}, - {file = "yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6"}, - {file = "yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8503ad47387b8ebd39cbbbdf0bf113e17330ffd339ba1144074da24c545f0069"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02ddb6756f8f4517a2d5e99d8b2f272488e18dd0bfbc802f31c16c6c20f22193"}, - {file = "yarl-1.18.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:67a283dd2882ac98cc6318384f565bffc751ab564605959df4752d42483ad889"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d980e0325b6eddc81331d3f4551e2a333999fb176fd153e075c6d1c2530aa8a8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b643562c12680b01e17239be267bc306bbc6aac1f34f6444d1bded0c5ce438ca"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c017a3b6df3a1bd45b9fa49a0f54005e53fbcad16633870104b66fa1a30a29d8"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75674776d96d7b851b6498f17824ba17849d790a44d282929c42dbb77d4f17ae"}, - {file = "yarl-1.18.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ccaa3a4b521b780a7e771cc336a2dba389a0861592bbce09a476190bb0c8b4b3"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2d06d3005e668744e11ed80812e61efd77d70bb7f03e33c1598c301eea20efbb"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:9d41beda9dc97ca9ab0b9888cb71f7539124bc05df02c0cff6e5acc5a19dcc6e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ba23302c0c61a9999784e73809427c9dbedd79f66a13d84ad1b1943802eaaf59"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6748dbf9bfa5ba1afcc7556b71cda0d7ce5f24768043a02a58846e4a443d808d"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0b0cad37311123211dc91eadcb322ef4d4a66008d3e1bdc404808992260e1a0e"}, - {file = "yarl-1.18.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0fb2171a4486bb075316ee754c6d8382ea6eb8b399d4ec62fde2b591f879778a"}, - {file = "yarl-1.18.3-cp311-cp311-win32.whl", hash = "sha256:61b1a825a13bef4a5f10b1885245377d3cd0bf87cba068e1d9a88c2ae36880e1"}, - {file = "yarl-1.18.3-cp311-cp311-win_amd64.whl", hash = "sha256:b9d60031cf568c627d028239693fd718025719c02c9f55df0a53e587aab951b5"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1dd4bdd05407ced96fed3d7f25dbbf88d2ffb045a0db60dbc247f5b3c5c25d50"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7c33dd1931a95e5d9a772d0ac5e44cac8957eaf58e3c8da8c1414de7dd27c576"}, - {file = "yarl-1.18.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:25b411eddcfd56a2f0cd6a384e9f4f7aa3efee14b188de13048c25b5e91f1640"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:436c4fc0a4d66b2badc6c5fc5ef4e47bb10e4fd9bf0c79524ac719a01f3607c2"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e35ef8683211db69ffe129a25d5634319a677570ab6b2eba4afa860f54eeaf75"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84b2deecba4a3f1a398df819151eb72d29bfeb3b69abb145a00ddc8d30094512"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00e5a1fea0fd4f5bfa7440a47eff01d9822a65b4488f7cff83155a0f31a2ecba"}, - {file = "yarl-1.18.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e883008013c0e4aef84dcfe2a0b172c4d23c2669412cf5b3371003941f72bb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a3f356548e34a70b0172d8890006c37be92995f62d95a07b4a42e90fba54272"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ccd17349166b1bee6e529b4add61727d3f55edb7babbe4069b5764c9587a8cc6"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b958ddd075ddba5b09bb0be8a6d9906d2ce933aee81100db289badbeb966f54e"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c7d79f7d9aabd6011004e33b22bc13056a3e3fb54794d138af57f5ee9d9032cb"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4891ed92157e5430874dad17b15eb1fda57627710756c27422200c52d8a4e393"}, - {file = "yarl-1.18.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ce1af883b94304f493698b00d0f006d56aea98aeb49d75ec7d98cd4a777e9285"}, - {file = "yarl-1.18.3-cp312-cp312-win32.whl", hash = "sha256:f91c4803173928a25e1a55b943c81f55b8872f0018be83e3ad4938adffb77dd2"}, - {file = "yarl-1.18.3-cp312-cp312-win_amd64.whl", hash = "sha256:7e2ee16578af3b52ac2f334c3b1f92262f47e02cc6193c598502bd46f5cd1477"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:90adb47ad432332d4f0bc28f83a5963f426ce9a1a8809f5e584e704b82685dcb"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:913829534200eb0f789d45349e55203a091f45c37a2674678744ae52fae23efa"}, - {file = "yarl-1.18.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ef9f7768395923c3039055c14334ba4d926f3baf7b776c923c93d80195624782"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88a19f62ff30117e706ebc9090b8ecc79aeb77d0b1f5ec10d2d27a12bc9f66d0"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e17c9361d46a4d5addf777c6dd5eab0715a7684c2f11b88c67ac37edfba6c482"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a74a13a4c857a84a845505fd2d68e54826a2cd01935a96efb1e9d86c728e186"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41f7ce59d6ee7741af71d82020346af364949314ed3d87553763a2df1829cc58"}, - {file = "yarl-1.18.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f52a265001d830bc425f82ca9eabda94a64a4d753b07d623a9f2863fde532b53"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:82123d0c954dc58db301f5021a01854a85bf1f3bb7d12ae0c01afc414a882ca2"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2ec9bbba33b2d00999af4631a3397d1fd78290c48e2a3e52d8dd72db3a067ac8"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fbd6748e8ab9b41171bb95c6142faf068f5ef1511935a0aa07025438dd9a9bc1"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:877d209b6aebeb5b16c42cbb377f5f94d9e556626b1bfff66d7b0d115be88d0a"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b464c4ab4bfcb41e3bfd3f1c26600d038376c2de3297760dfe064d2cb7ea8e10"}, - {file = "yarl-1.18.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d39d351e7faf01483cc7ff7c0213c412e38e5a340238826be7e0e4da450fdc8"}, - {file = "yarl-1.18.3-cp313-cp313-win32.whl", hash = "sha256:61ee62ead9b68b9123ec24bc866cbef297dd266175d53296e2db5e7f797f902d"}, - {file = "yarl-1.18.3-cp313-cp313-win_amd64.whl", hash = "sha256:578e281c393af575879990861823ef19d66e2b1d0098414855dd367e234f5b3c"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:61e5e68cb65ac8f547f6b5ef933f510134a6bf31bb178be428994b0cb46c2a04"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe57328fbc1bfd0bd0514470ac692630f3901c0ee39052ae47acd1d90a436719"}, - {file = "yarl-1.18.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a440a2a624683108a1b454705ecd7afc1c3438a08e890a1513d468671d90a04e"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09c7907c8548bcd6ab860e5f513e727c53b4a714f459b084f6580b49fa1b9cee"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4f6450109834af88cb4cc5ecddfc5380ebb9c228695afc11915a0bf82116789"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9ca04806f3be0ac6d558fffc2fdf8fcef767e0489d2684a21912cc4ed0cd1b8"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77a6e85b90a7641d2e07184df5557132a337f136250caafc9ccaa4a2a998ca2c"}, - {file = "yarl-1.18.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6333c5a377c8e2f5fae35e7b8f145c617b02c939d04110c76f29ee3676b5f9a5"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0b3c92fa08759dbf12b3a59579a4096ba9af8dd344d9a813fc7f5070d86bbab1"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:4ac515b860c36becb81bb84b667466885096b5fc85596948548b667da3bf9f24"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:045b8482ce9483ada4f3f23b3774f4e1bf4f23a2d5c912ed5170f68efb053318"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:a4bb030cf46a434ec0225bddbebd4b89e6471814ca851abb8696170adb163985"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:54d6921f07555713b9300bee9c50fb46e57e2e639027089b1d795ecd9f7fa910"}, - {file = "yarl-1.18.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1d407181cfa6e70077df3377938c08012d18893f9f20e92f7d2f314a437c30b1"}, - {file = "yarl-1.18.3-cp39-cp39-win32.whl", hash = "sha256:ac36703a585e0929b032fbaab0707b75dc12703766d0b53486eabd5139ebadd5"}, - {file = "yarl-1.18.3-cp39-cp39-win_amd64.whl", hash = "sha256:ba87babd629f8af77f557b61e49e7c7cac36f22f871156b91e10a6e9d4f829e9"}, - {file = "yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b"}, - {file = "yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f1f6670b9ae3daedb325fa55fbe31c22c8228f6e0b513772c2e1c623caa6ab22"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85a231fa250dfa3308f3c7896cc007a47bc76e9e8e8595c20b7426cac4884c62"}, + {file = "yarl-1.20.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1a06701b647c9939d7019acdfa7ebbfbb78ba6aa05985bb195ad716ea759a569"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7595498d085becc8fb9203aa314b136ab0516c7abd97e7d74f7bb4eb95042abe"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af5607159085dcdb055d5678fc2d34949bd75ae6ea6b4381e784bbab1c3aa195"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:95b50910e496567434cb77a577493c26bce0f31c8a305135f3bda6a2483b8e10"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b594113a301ad537766b4e16a5a6750fcbb1497dcc1bc8a4daae889e6402a634"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:083ce0393ea173cd37834eb84df15b6853b555d20c52703e21fbababa8c129d2"}, + {file = "yarl-1.20.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f1a350a652bbbe12f666109fbddfdf049b3ff43696d18c9ab1531fbba1c977a"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fb0caeac4a164aadce342f1597297ec0ce261ec4532bbc5a9ca8da5622f53867"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d88cc43e923f324203f6ec14434fa33b85c06d18d59c167a0637164863b8e995"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e52d6ed9ea8fd3abf4031325dc714aed5afcbfa19ee4a89898d663c9976eb487"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ce360ae48a5e9961d0c730cf891d40698a82804e85f6e74658fb175207a77cb2"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:06d06c9d5b5bc3eb56542ceeba6658d31f54cf401e8468512447834856fb0e61"}, + {file = "yarl-1.20.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c27d98f4e5c4060582f44e58309c1e55134880558f1add7a87c1bc36ecfade19"}, + {file = "yarl-1.20.0-cp310-cp310-win32.whl", hash = "sha256:f4d3fa9b9f013f7050326e165c3279e22850d02ae544ace285674cb6174b5d6d"}, + {file = "yarl-1.20.0-cp310-cp310-win_amd64.whl", hash = "sha256:bc906b636239631d42eb8a07df8359905da02704a868983265603887ed68c076"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fdb5204d17cb32b2de2d1e21c7461cabfacf17f3645e4b9039f210c5d3378bf3"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:eaddd7804d8e77d67c28d154ae5fab203163bd0998769569861258e525039d2a"}, + {file = "yarl-1.20.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:634b7ba6b4a85cf67e9df7c13a7fb2e44fa37b5d34501038d174a63eaac25ee2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d409e321e4addf7d97ee84162538c7258e53792eb7c6defd0c33647d754172e"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ea52f7328a36960ba3231c6677380fa67811b414798a6e071c7085c57b6d20a9"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c8703517b924463994c344dcdf99a2d5ce9eca2b6882bb640aa555fb5efc706a"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:077989b09ffd2f48fb2d8f6a86c5fef02f63ffe6b1dd4824c76de7bb01e4f2e2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0acfaf1da020253f3533526e8b7dd212838fdc4109959a2c53cafc6db611bff2"}, + {file = "yarl-1.20.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4230ac0b97ec5eeb91d96b324d66060a43fd0d2a9b603e3327ed65f084e41f8"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0a6a1e6ae21cdd84011c24c78d7a126425148b24d437b5702328e4ba640a8902"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:86de313371ec04dd2531f30bc41a5a1a96f25a02823558ee0f2af0beaa7ca791"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dd59c9dd58ae16eaa0f48c3d0cbe6be8ab4dc7247c3ff7db678edecbaf59327f"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a0bc5e05f457b7c1994cc29e83b58f540b76234ba6b9648a4971ddc7f6aa52da"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c9471ca18e6aeb0e03276b5e9b27b14a54c052d370a9c0c04a68cefbd1455eb4"}, + {file = "yarl-1.20.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:40ed574b4df723583a26c04b298b283ff171bcc387bc34c2683235e2487a65a5"}, + {file = "yarl-1.20.0-cp311-cp311-win32.whl", hash = "sha256:db243357c6c2bf3cd7e17080034ade668d54ce304d820c2a58514a4e51d0cfd6"}, + {file = "yarl-1.20.0-cp311-cp311-win_amd64.whl", hash = "sha256:8c12cd754d9dbd14204c328915e23b0c361b88f3cffd124129955e60a4fbfcfb"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e06b9f6cdd772f9b665e5ba8161968e11e403774114420737f7884b5bd7bdf6f"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b9ae2fbe54d859b3ade40290f60fe40e7f969d83d482e84d2c31b9bff03e359e"}, + {file = "yarl-1.20.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d12b8945250d80c67688602c891237994d203d42427cb14e36d1a732eda480e"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:087e9731884621b162a3e06dc0d2d626e1542a617f65ba7cc7aeab279d55ad33"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69df35468b66c1a6e6556248e6443ef0ec5f11a7a4428cf1f6281f1879220f58"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b2992fe29002fd0d4cbaea9428b09af9b8686a9024c840b8a2b8f4ea4abc16f"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4c903e0b42aab48abfbac668b5a9d7b6938e721a6341751331bcd7553de2dcae"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf099e2432131093cc611623e0b0bcc399b8cddd9a91eded8bfb50402ec35018"}, + {file = "yarl-1.20.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7f62f5dc70a6c763bec9ebf922be52aa22863d9496a9a30124d65b489ea672"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:54ac15a8b60382b2bcefd9a289ee26dc0920cf59b05368c9b2b72450751c6eb8"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:25b3bc0763a7aca16a0f1b5e8ef0f23829df11fb539a1b70476dcab28bd83da7"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2586e36dc070fc8fad6270f93242124df68b379c3a251af534030a4a33ef594"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:866349da9d8c5290cfefb7fcc47721e94de3f315433613e01b435473be63daa6"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:33bb660b390a0554d41f8ebec5cd4475502d84104b27e9b42f5321c5192bfcd1"}, + {file = "yarl-1.20.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:737e9f171e5a07031cbee5e9180f6ce21a6c599b9d4b2c24d35df20a52fabf4b"}, + {file = "yarl-1.20.0-cp312-cp312-win32.whl", hash = "sha256:839de4c574169b6598d47ad61534e6981979ca2c820ccb77bf70f4311dd2cc64"}, + {file = "yarl-1.20.0-cp312-cp312-win_amd64.whl", hash = "sha256:3d7dbbe44b443b0c4aa0971cb07dcb2c2060e4a9bf8d1301140a33a93c98e18c"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2137810a20b933b1b1b7e5cf06a64c3ed3b4747b0e5d79c9447c00db0e2f752f"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:447c5eadd750db8389804030d15f43d30435ed47af1313303ed82a62388176d3"}, + {file = "yarl-1.20.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:42fbe577272c203528d402eec8bf4b2d14fd49ecfec92272334270b850e9cd7d"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18e321617de4ab170226cd15006a565d0fa0d908f11f724a2c9142d6b2812ab0"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4345f58719825bba29895011e8e3b545e6e00257abb984f9f27fe923afca2501"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d9b980d7234614bc4674468ab173ed77d678349c860c3af83b1fffb6a837ddc"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af4baa8a445977831cbaa91a9a84cc09debb10bc8391f128da2f7bd070fc351d"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123393db7420e71d6ce40d24885a9e65eb1edefc7a5228db2d62bcab3386a5c0"}, + {file = "yarl-1.20.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab47acc9332f3de1b39e9b702d9c916af7f02656b2a86a474d9db4e53ef8fd7a"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4a34c52ed158f89876cba9c600b2c964dfc1ca52ba7b3ab6deb722d1d8be6df2"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:04d8cfb12714158abf2618f792c77bc5c3d8c5f37353e79509608be4f18705c9"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:7dc63ad0d541c38b6ae2255aaa794434293964677d5c1ec5d0116b0e308031f5"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d02b591a64e4e6ca18c5e3d925f11b559c763b950184a64cf47d74d7e41877"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:95fc9876f917cac7f757df80a5dda9de59d423568460fe75d128c813b9af558e"}, + {file = "yarl-1.20.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb769ae5760cd1c6a712135ee7915f9d43f11d9ef769cb3f75a23e398a92d384"}, + {file = "yarl-1.20.0-cp313-cp313-win32.whl", hash = "sha256:70e0c580a0292c7414a1cead1e076c9786f685c1fc4757573d2967689b370e62"}, + {file = "yarl-1.20.0-cp313-cp313-win_amd64.whl", hash = "sha256:4c43030e4b0af775a85be1fa0433119b1565673266a70bf87ef68a9d5ba3174c"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b6c4c3d0d6a0ae9b281e492b1465c72de433b782e6b5001c8e7249e085b69051"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8681700f4e4df891eafa4f69a439a6e7d480d64e52bf460918f58e443bd3da7d"}, + {file = "yarl-1.20.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:84aeb556cb06c00652dbf87c17838eb6d92cfd317799a8092cee0e570ee11229"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f166eafa78810ddb383e930d62e623d288fb04ec566d1b4790099ae0f31485f1"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5d3d6d14754aefc7a458261027a562f024d4f6b8a798adb472277f675857b1eb"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a8f64df8ed5d04c51260dbae3cc82e5649834eebea9eadfd829837b8093eb00"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4d9949eaf05b4d30e93e4034a7790634bbb41b8be2d07edd26754f2e38e491de"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c366b254082d21cc4f08f522ac201d0d83a8b8447ab562732931d31d80eb2a5"}, + {file = "yarl-1.20.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91bc450c80a2e9685b10e34e41aef3d44ddf99b3a498717938926d05ca493f6a"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c2aa4387de4bc3a5fe158080757748d16567119bef215bec643716b4fbf53f9"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d2cbca6760a541189cf87ee54ff891e1d9ea6406079c66341008f7ef6ab61145"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:798a5074e656f06b9fad1a162be5a32da45237ce19d07884d0b67a0aa9d5fdda"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:f106e75c454288472dbe615accef8248c686958c2e7dd3b8d8ee2669770d020f"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3b60a86551669c23dc5445010534d2c5d8a4e012163218fc9114e857c0586fdd"}, + {file = "yarl-1.20.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3e429857e341d5e8e15806118e0294f8073ba9c4580637e59ab7b238afca836f"}, + {file = "yarl-1.20.0-cp313-cp313t-win32.whl", hash = "sha256:65a4053580fe88a63e8e4056b427224cd01edfb5f951498bfefca4052f0ce0ac"}, + {file = "yarl-1.20.0-cp313-cp313t-win_amd64.whl", hash = "sha256:53b2da3a6ca0a541c1ae799c349788d480e5144cac47dba0266c7cb6c76151fe"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:119bca25e63a7725b0c9d20ac67ca6d98fa40e5a894bd5d4686010ff73397914"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35d20fb919546995f1d8c9e41f485febd266f60e55383090010f272aca93edcc"}, + {file = "yarl-1.20.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:484e7a08f72683c0f160270566b4395ea5412b4359772b98659921411d32ad26"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d8a3d54a090e0fff5837cd3cc305dd8a07d3435a088ddb1f65e33b322f66a94"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f0cf05ae2d3d87a8c9022f3885ac6dea2b751aefd66a4f200e408a61ae9b7f0d"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a884b8974729e3899d9287df46f015ce53f7282d8d3340fa0ed57536b440621c"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8d8aa8dd89ffb9a831fedbcb27d00ffd9f4842107d52dc9d57e64cb34073d5c"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4e88d6c3c8672f45a30867817e4537df1bbc6f882a91581faf1f6d9f0f1b5a"}, + {file = "yarl-1.20.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdb77efde644d6f1ad27be8a5d67c10b7f769804fff7a966ccb1da5a4de4b656"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:4ba5e59f14bfe8d261a654278a0f6364feef64a794bd456a8c9e823071e5061c"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:d0bf955b96ea44ad914bc792c26a0edcd71b4668b93cbcd60f5b0aeaaed06c64"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:27359776bc359ee6eaefe40cb19060238f31228799e43ebd3884e9c589e63b20"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:04d9c7a1dc0a26efb33e1acb56c8849bd57a693b85f44774356c92d610369efa"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:faa709b66ae0e24c8e5134033187a972d849d87ed0a12a0366bedcc6b5dc14a5"}, + {file = "yarl-1.20.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:44869ee8538208fe5d9342ed62c11cc6a7a1af1b3d0bb79bb795101b6e77f6e0"}, + {file = "yarl-1.20.0-cp39-cp39-win32.whl", hash = "sha256:b7fa0cb9fd27ffb1211cde944b41f5c67ab1c13a13ebafe470b1e206b8459da8"}, + {file = "yarl-1.20.0-cp39-cp39-win_amd64.whl", hash = "sha256:d4fad6e5189c847820288286732075f213eabf81be4d08d6cc309912e62be5b7"}, + {file = "yarl-1.20.0-py3-none-any.whl", hash = "sha256:5d0fe6af927a47a230f31e6004621fd0959eaa915fc62acfafa67ff7229a3124"}, + {file = "yarl-1.20.0.tar.gz", hash = "sha256:686d51e51ee5dfe62dec86e4866ee0e9ed66df700d55c828a615640adc885307"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" -propcache = ">=0.2.0" +propcache = ">=0.2.1" [[package]] name = "zipp" @@ -3956,4 +4058,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "89c6da87f5e73c0d7301af6eee5c75adee21029a57dd4c5fd58f30264538ca0f" +content-hash = "ee0d3ab758d5e2dfc4e0e984b7064f301bb3dd800b9a82a39358d4375a1e3c8e" diff --git a/pyproject.toml b/pyproject.toml index 8e8d647aa..60848d481 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-app" -version = "0.2.0-rc260" +version = "0.2.0-rc173" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" @@ -9,7 +9,7 @@ include = [] [tool.poetry.dependencies] python = ">=3.9,<3.12" -olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "6cfb306a4c4234d4c570fba9209159749c1ce71f"} +olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "920957b1871a533a3a63f1162d9c6d10625226a8"} [build-system] requires = ["poetry-core"] diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index d420712d8..000000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Tests.""" diff --git a/tests/test_services_manage.py b/tests/test_services_manage.py deleted file mode 100644 index 03bb9946d..000000000 --- a/tests/test_services_manage.py +++ /dev/null @@ -1,344 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2024 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Tests for services.service module.""" - -import random -import string -import typing as t -from pathlib import Path - -import pytest -from deepdiff import DeepDiff - -from operate.cli import OperateApp -from operate.operate_types import ServiceTemplate -from operate.services.manage import ServiceManager - -from .test_services_service import DEFAULT_CONFIG_KWARGS - - -ROOT_PATH = Path(__file__).resolve().parent -OPERATE_HOME = ROOT_PATH / ".operate_test" - - -@pytest.fixture -def random_string() -> str: - """random_string""" - length = 8 - chars = string.ascii_letters + string.digits - return "".join(random.choices(chars, k=length)) # nosec B311 - - -def get_template(**kwargs: t.Any) -> ServiceTemplate: - """get_template""" - - return { - "name": kwargs.get("name"), - "hash": kwargs.get("hash"), - "description": kwargs.get("description"), - "image": "https://image_url", - "service_version": "", - "home_chain": "gnosis", - "configurations": { - "gnosis": { - "staking_program_id": kwargs.get("staking_program_id"), - "nft": kwargs.get("nft"), - "rpc": "http://localhost:8545", - "threshold": kwargs.get("threshold"), - "agent_id": kwargs.get("agent_id"), - "use_staking": kwargs.get("use_staking"), - "use_mech_marketplace": kwargs.get("use_mech_marketplace"), - "cost_of_bond": kwargs.get("cost_of_bond"), - "fund_requirements": { - "0x0000000000000000000000000000000000000000": { - "agent": kwargs.get("fund_requirements_agent"), - "safe": kwargs.get("fund_requirements_safe"), - } - }, - "fallback_chain_params": {}, - } - }, - "env_variables": { - "VAR1": { - "name": "var1_name", - "description": "var1_description", - "value": "var1_value", - "provision_type": "var1_provision_type", - }, - "VAR2": { - "name": "var2_name", - "description": "var2_description", - "value": "var2_value", - "provision_type": "var2_provision_type", - }, - }, - } - - -class TestServiceManager: - """Tests for services.manager.ServiceManager class.""" - - @pytest.mark.parametrize("update_new_var", [True, False]) - @pytest.mark.parametrize("update_update_var", [True, False]) - @pytest.mark.parametrize("update_name", [True, False]) - @pytest.mark.parametrize("update_description", [True, False]) - @pytest.mark.parametrize("update_hash", [True, False]) - def test_service_manager_partial_update( - self, - update_new_var: bool, - update_update_var: bool, - update_name: bool, - update_description: bool, - update_hash: bool, - tmp_path: Path, - random_string: str, - ) -> None: - """Test operate.service_manager().update()""" - - operate = OperateApp( - home=tmp_path / ".operate_test", - ) - operate.setup() - password = random_string - operate.create_user_account(password=password) - operate.password = password - service_manager = operate.service_manager() - service_template = get_template(**DEFAULT_CONFIG_KWARGS) - service = service_manager.create(service_template) - service_config_id = service.service_config_id - service_json = service_manager.load(service_config_id).json - - new_hash = "bafybeicts6zhavxzz2rxahz3wzs2pzamoq64n64wp4q4cdanfuz7id6c2q" - VAR2_updated_attributes = { - "name": "var2_name_updated", - "description": "var2_description_updated", - "value": "var2_value_updated", - "provision_type": "var2_provision_type_updated", - "extra_attr": "extra_val", - } - - VAR3_attributes = { - "name": "var3_name", - "description": "var3_description", - "value": "var3_value", - "provision_type": "var3_provision_type", - } - - # Partial update - update_template: t.Dict = {} - expected_service_json = service_json.copy() - - if update_new_var: - update_template["env_variables"] = update_template.get("env_variables", {}) - update_template["env_variables"]["VAR3"] = VAR3_attributes - expected_service_json["env_variables"]["VAR3"] = VAR3_attributes - - if update_update_var: - update_template["env_variables"] = update_template.get("env_variables", {}) - update_template["env_variables"]["VAR2"] = VAR2_updated_attributes - expected_service_json["env_variables"]["VAR2"] = VAR2_updated_attributes - - if update_name: - update_template["name"] = "name_updated" - expected_service_json["name"] = "name_updated" - - if update_description: - update_template["description"] = "description_updated" - expected_service_json["description"] = "description_updated" - - if update_hash: - update_template["hash"] = new_hash - expected_service_json["hash"] = new_hash - - service_manager.update( - service_config_id=service_config_id, - service_template=update_template, - allow_different_service_public_id=False, - partial_update=True, - ) - service_json = service_manager.load(service_config_id).json - - if update_hash: - timestamp = max(service_json["hash_history"].keys()) - expected_service_json["hash_history"][timestamp] = new_hash - - diff = DeepDiff(service_json, expected_service_json) - if diff: - print(diff) - - assert not diff, "Updated service does not match expected service." - - @pytest.mark.parametrize("update_new_var", [True, False]) - @pytest.mark.parametrize("update_update_var", [True, False]) - @pytest.mark.parametrize("update_delete_var", [True, False]) - @pytest.mark.parametrize("update_name", [True, False]) - @pytest.mark.parametrize("update_description", [True, False]) - @pytest.mark.parametrize("update_hash", [True, False]) - def test_service_manager_update( - self, - update_new_var: bool, - update_update_var: bool, - update_delete_var: bool, - update_name: bool, - update_description: bool, - update_hash: bool, - tmp_path: Path, - random_string: str, - ) -> None: - """Test operate.service_manager().update()""" - - operate = OperateApp( - home=tmp_path / ".operate_test", - ) - operate.setup() - password = random_string - operate.create_user_account(password=password) - operate.password = password - service_manager = operate.service_manager() - service_template = get_template(**DEFAULT_CONFIG_KWARGS) - service = service_manager.create(service_template) - service_config_id = service.service_config_id - service_json = service_manager.load(service_config_id).json - - new_hash = "bafybeicts6zhavxzz2rxahz3wzs2pzamoq64n64wp4q4cdanfuz7id6c2q" - VAR2_updated_attributes = { - "name": "var2_name_updated", - "description": "var2_description_updated", - "value": "var2_value_updated", - "provision_type": "var2_provision_type_updated", - "extra_attr": "extra_val", - } - - VAR3_attributes = { - "name": "var3_name", - "description": "var3_description", - "value": "var3_value", - "provision_type": "var3_provision_type", - } - - # Partial update - update_template: t.Dict = service_template.copy() - expected_service_json = service_json.copy() - - if update_new_var: - update_template["env_variables"] = update_template.get("env_variables", {}) - update_template["env_variables"]["VAR3"] = VAR3_attributes - expected_service_json["env_variables"]["VAR3"] = VAR3_attributes - - if update_update_var: - update_template["env_variables"] = update_template.get("env_variables", {}) - update_template["env_variables"]["VAR2"] = VAR2_updated_attributes - expected_service_json["env_variables"]["VAR2"] = VAR2_updated_attributes - - if update_delete_var: - update_template["env_variables"] = update_template.get("env_variables", {}) - del update_template["env_variables"]["VAR1"] - del expected_service_json["env_variables"]["VAR1"] - - if update_name: - update_template["name"] = "name_updated" - expected_service_json["name"] = "name_updated" - - if update_description: - update_template["description"] = "description_updated" - expected_service_json["description"] = "description_updated" - - if update_hash: - update_template["hash"] = new_hash - expected_service_json["hash"] = new_hash - - service_manager.update( - service_config_id=service_config_id, - service_template=update_template, - allow_different_service_public_id=False, - partial_update=False, - ) - service_json = service_manager.load(service_config_id).json - - if update_hash: - timestamp = max(service_json["hash_history"].keys()) - expected_service_json["hash_history"][timestamp] = new_hash - - diff = DeepDiff(service_json, expected_service_json) - if diff: - print(diff) - - assert not diff, "Updated service does not match expected service." - - @pytest.mark.parametrize( - "topup1, threshold1, balance1, topup2, threshold2, balance2, topup3, threshold3, balance3, sender_balance, minimum_refill_required, recommended_refill_required", - [ - (10, 5, 1, 0, 0, 0, 0, 0, 0, 1, 3, 8), - (10, 5, 1, 10, 5, 8, 0, 0, 0, 1, 3, 8), - (10, 5, 8, 10, 5, 1, 0, 0, 0, 1, 3, 8), - (10, 5, 8, 10, 5, 1, 10, 5, 1, 1, 7, 17), - (10, 5, 6, 10, 5, 6, 0, 0, 0, 1, 0, 0), - (10, 5, 2, 20, 10, 7, 0, 0, 0, 4, 2, 17), - (10, 5, 2, 20, 10, 3, 0, 0, 0, 4, 6, 21), - (15, 15, 10, 0, 0, 0, 0, 0, 0, 0, 5, 5), - ], - ) - def test_service_manager_compute_refill_requirements( - self, - topup1: int, - threshold1: int, - balance1: int, - topup2: int, - threshold2: int, - balance2: int, - topup3: int, - threshold3: int, - balance3: int, - sender_balance: int, - minimum_refill_required: int, - recommended_refill_required: int, - ) -> None: - """Test operate.service_manager()._compute_refill_requirements()""" - - asset_funding_values = {} - asset_funding_values["0x1"] = { - "topup": topup1, - "threshold": threshold1, - "balance": balance1, - } - asset_funding_values["0x2"] = { - "topup": topup2, - "threshold": threshold2, - "balance": balance2, - } - asset_funding_values["0x3"] = { - "topup": topup3, - "threshold": threshold3, - "balance": balance3, - } - - expected_result = { - "minimum_refill": minimum_refill_required, - "recommended_refill": recommended_refill_required, - } - result = ServiceManager._compute_refill_requirement( - asset_funding_values, sender_balance - ) - - diff = DeepDiff(result, expected_result) - if diff: - print(diff) - - assert not diff, "Failed to compute refill requirements." diff --git a/tests/test_services_service.py b/tests/test_services_service.py deleted file mode 100644 index 93ba084eb..000000000 --- a/tests/test_services_service.py +++ /dev/null @@ -1,360 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2024 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Tests for services.service module.""" - -import json -import typing as t -from pathlib import Path - -import pytest -from deepdiff import DeepDiff - -from operate.services.service import ( - SERVICE_CONFIG_PREFIX, - SERVICE_CONFIG_VERSION, - Service, -) - - -DEFAULT_CONFIG_KWARGS = { - "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", - "use_staking": True, - "use_mech_marketplace": False, - "rpc": "https://rpc.com", - "service_config_id": "sc-00000000-0000-0000-0000-000000000000", - "hash_timestamp": 1704063600, - "token": 42, - "staked": True, - "on_chain_state": 4, - "staking_program_id": "staking_program_1", - "threshold": 1, - "agent_id": 14, - "cost_of_bond": 10000000000000000, - "fund_requirements_agent": 100000000000000000, - "fund_requirements_safe": 5000000000000000000, - "nft": "bafybeinft", - "name": "Test Service", - "description": "Service description", - "keys_address_0": "0x0000000000000000000000000000000000000001", - "keys_private_key_0": "0x0000000000000000000000000000000000000000000000000000000000000001", - "instance_0": "0x0000000000000000000000000000000000000001", - "multisig": "0x0000000000000000000000000000000000000020", - "service_config_id": "sc-00000000-0000-0000-0000-000000000000", -} - - -def get_config_json_data_v0(**kwargs: t.Any) -> t.Dict[str, t.Any]: - """get_config_json_data_v0""" - - return { - "hash": kwargs.get("hash"), - "keys": [ - { - "ledger": 0, - "address": kwargs.get("keys_address_0"), - "private_key": kwargs.get("keys_private_key_0"), - } - ], - "ledger_config": {"rpc": kwargs.get("rpc"), "type": 0, "chain": 2}, - "chain_data": { - "instances": [kwargs.get("instance_0")], - "token": kwargs.get("token"), - "multisig": kwargs.get("multisig"), - "staked": True, - "on_chain_state": kwargs.get("on_chain_state"), - "user_params": { - "nft": kwargs.get("nft"), - "agent_id": kwargs.get("agent_id"), - "threshold": kwargs.get("threshold"), - "use_staking": kwargs.get("use_staking"), - "cost_of_bond": kwargs.get("cost_of_bond"), - "olas_cost_of_bond": 10000000000000000000, - "olas_required_to_stake": 10000000000000000000, - "fund_requirements": { - "agent": kwargs.get("fund_requirements_agent"), - "safe": kwargs.get("fund_requirements_safe"), - }, - }, - }, - "service_path": f"/home/user/.operate/services/{kwargs.get('hash')}/trader_pearl", - "name": kwargs.get("name"), - } - - -def get_config_json_data_v2(**kwargs: t.Any) -> t.Dict[str, t.Any]: - """get_config_json_data_v2""" - - return { - "version": 2, - "hash": kwargs.get("hash"), - "keys": [ - { - "ledger": 0, - "address": kwargs.get("keys_address_0"), - "private_key": kwargs.get("keys_private_key_0"), - } - ], - "home_chain_id": "100", - "chain_configs": { - "100": { - "ledger_config": {"rpc": kwargs.get("rpc"), "type": 0, "chain": 2}, - "chain_data": { - "instances": [kwargs.get("instance_0")], - "token": kwargs.get("token"), - "multisig": kwargs.get("multisig"), - "staked": True, - "on_chain_state": kwargs.get("on_chain_state"), - "user_params": { - "staking_program_id": kwargs.get("staking_program_id"), - "nft": kwargs.get("nft"), - "threshold": kwargs.get("threshold"), - "use_staking": kwargs.get("use_staking"), - "cost_of_bond": kwargs.get("cost_of_bond"), - "fund_requirements": { - "agent": kwargs.get("fund_requirements_agent"), - "safe": kwargs.get("fund_requirements_safe"), - }, - }, - }, - } - }, - "service_path": f"/home/user/.operate/services/{kwargs.get('hash')}/trader_pearl", - "name": kwargs.get("name"), - } - - -def get_config_json_data_v3(**kwargs: t.Any) -> t.Dict[str, t.Any]: - """get_config_json_data_v3""" - - return { - "version": 3, - "hash": kwargs.get("hash"), - "keys": [ - { - "ledger": 0, - "address": kwargs.get("keys_address_0"), - "private_key": kwargs.get("keys_private_key_0"), - } - ], - "home_chain_id": "100", - "chain_configs": { - "100": { - "ledger_config": {"rpc": kwargs.get("rpc"), "type": 0, "chain": 2}, - "chain_data": { - "instances": [kwargs.get("instance_0")], - "token": kwargs.get("token"), - "multisig": kwargs.get("multisig"), - "staked": True, - "on_chain_state": kwargs.get("on_chain_state"), - "user_params": { - "staking_program_id": kwargs.get("staking_program_id"), - "nft": kwargs.get("nft"), - "threshold": kwargs.get("threshold"), - "use_staking": kwargs.get("use_staking"), - "use_mech_marketplace": kwargs.get("use_mech_marketplace"), - "cost_of_bond": kwargs.get("cost_of_bond"), - "fund_requirements": { - "agent": kwargs.get("fund_requirements_agent"), - "safe": kwargs.get("fund_requirements_safe"), - }, - }, - }, - } - }, - "service_path": f"/home/user/.operate/services/{kwargs.get('hash')}/trader_pearl", - "name": kwargs.get("name"), - } - - -def get_config_json_data_v4(**kwargs: t.Any) -> t.Dict[str, t.Any]: - """get_config_json_data_v4""" - - return { - "version": 4, - "service_config_id": kwargs.get("service_config_id"), - "hash": kwargs.get("hash"), - "hash_history": {kwargs.get("hash_timestamp"): kwargs.get("hash")}, - "keys": [ - { - "ledger": "ethereum", - "address": kwargs.get("keys_address_0"), - "private_key": kwargs.get("keys_private_key_0"), - } - ], - "home_chain": "gnosis", - "chain_configs": { - "gnosis": { - "ledger_config": {"rpc": kwargs.get("rpc"), "chain": "gnosis"}, - "chain_data": { - "instances": [kwargs.get("instance_0")], - "token": kwargs.get("token"), - "multisig": kwargs.get("multisig"), - "staked": kwargs.get("staked"), - "on_chain_state": kwargs.get("on_chain_state"), - "user_params": { - "staking_program_id": kwargs.get("staking_program_id"), - "nft": kwargs.get("nft"), - "threshold": kwargs.get("threshold"), - "agent_id": kwargs.get("agent_id"), - "use_staking": kwargs.get("use_staking"), - "use_mech_marketplace": kwargs.get("use_mech_marketplace"), - "cost_of_bond": kwargs.get("cost_of_bond"), - "fund_requirements": { - "agent": kwargs.get("fund_requirements_agent"), - "safe": kwargs.get("fund_requirements_safe"), - }, - }, - }, - } - }, - "description": kwargs.get("description"), - "env_variables": {}, - "service_path": f"/home/user/.operate/services/{kwargs.get('service_config_id')}/trader_pearl", - "name": kwargs.get("name"), - } - - -def get_config_json_data_v5(**kwargs: t.Any) -> t.Dict[str, t.Any]: - """get_config_json_data_v4""" - - return { - "version": 5, - "service_config_id": kwargs.get("service_config_id"), - "hash": kwargs.get("hash"), - "hash_history": {kwargs.get("hash_timestamp"): kwargs.get("hash")}, - "keys": [ - { - "ledger": "ethereum", - "address": kwargs.get("keys_address_0"), - "private_key": kwargs.get("keys_private_key_0"), - } - ], - "home_chain": "gnosis", - "chain_configs": { - "gnosis": { - "ledger_config": {"rpc": kwargs.get("rpc"), "chain": "gnosis"}, - "chain_data": { - "instances": [kwargs.get("instance_0")], - "token": kwargs.get("token"), - "multisig": kwargs.get("multisig"), - "staked": kwargs.get("staked"), - "on_chain_state": kwargs.get("on_chain_state"), - "user_params": { - "staking_program_id": kwargs.get("staking_program_id"), - "nft": kwargs.get("nft"), - "threshold": kwargs.get("threshold"), - "agent_id": kwargs.get("agent_id"), - "use_staking": kwargs.get("use_staking"), - "use_mech_marketplace": kwargs.get("use_mech_marketplace"), - "cost_of_bond": kwargs.get("cost_of_bond"), - "fund_requirements": { - "0x0000000000000000000000000000000000000000": { - "agent": kwargs.get("fund_requirements_agent"), - "safe": kwargs.get("fund_requirements_safe"), - } - }, - }, - }, - } - }, - "description": kwargs.get("description"), - "env_variables": {}, - "service_path": kwargs.get("service_path"), - "name": kwargs.get("name"), - } - - -get_expected_data = get_config_json_data_v5 - - -class TestService: - """Tests for services.service.Service class.""" - - @pytest.mark.parametrize( - "staking_program_id", ["staking_program_1", "staking_program_2"] - ) - @pytest.mark.parametrize("use_mech_marketplace", [True]) - @pytest.mark.parametrize("use_staking", [True]) - @pytest.mark.parametrize( - "get_config_json_data", - [ - get_config_json_data_v0, - get_config_json_data_v2, - get_config_json_data_v3, - get_config_json_data_v4, - ], - ) - def test_service_migrate_format( - self, - get_config_json_data: t.Callable[..., t.Dict[str, t.Any]], - use_staking: bool, - use_mech_marketplace: bool, - staking_program_id: str, - tmp_path: Path, - ) -> None: - """Test services.service.Service.migrate_format()""" - - config_kwargs = DEFAULT_CONFIG_KWARGS.copy() - config_kwargs["use_staking"] = use_staking - config_kwargs["use_mech_marketplace"] = use_mech_marketplace - config_kwargs["staking_program"] = staking_program_id - old_config_json_data = get_config_json_data(**config_kwargs) - - # Emulate an existing service directory contents - service_config_dir = tmp_path / old_config_json_data.get( - "service_config_id", old_config_json_data.get("hash") - ) - service_config_dir.mkdir(parents=True, exist_ok=True) - - config_json_path = service_config_dir / "config.json" - with open(config_json_path, "w", encoding="utf-8") as file: - json.dump(old_config_json_data, file, indent=4) - - # Migrate the service using Service.migrate_format and read the resulting - # migrated data - Service.migrate_format(service_config_dir) - - migrated_config_dir = next(tmp_path.glob(f"{SERVICE_CONFIG_PREFIX}*/")) - new_config_json_path = migrated_config_dir / "config.json" - with open(new_config_json_path, "r", encoding="utf-8") as file: - migrated_data = json.load(file) - - # Construct the expected data - if old_config_json_data.get("version", 0) < 2: - config_kwargs["staking_program_id"] = "pearl_alpha" - - if old_config_json_data.get("version", 0) < 3: - config_kwargs["use_mech_marketplace"] = False - - if old_config_json_data.get("version", 0) < 4: - config_kwargs["description"] = config_kwargs["name"] - - config_kwargs["service_config_id"] = migrated_config_dir.name - config_kwargs["version"] = SERVICE_CONFIG_VERSION - config_kwargs["hash_timestamp"] = list(migrated_data["hash_history"].keys())[0] - config_kwargs["service_path"] = str(migrated_config_dir / "trader_pearl") - - expected_data = get_expected_data(**config_kwargs) - - diff = DeepDiff(migrated_data, expected_data) - if diff: - print(diff) - - assert not diff, "Migrated data does not match expected data." diff --git a/tests/test_wallet_master.py b/tests/test_wallet_master.py deleted file mode 100644 index 53b7a4b7b..000000000 --- a/tests/test_wallet_master.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2024 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Test for wallet.master module.""" diff --git a/yarn.lock b/yarn.lock index 2546afa42..c9ed6e7c6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -737,11 +737,6 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.2.0.tgz#a3150eeb09cc7ab207ebf6d7b9ad311a9bdbed12" integrity sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ== -"@noble/hashes@1.5.0": - version "1.5.0" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0" - integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== - "@noble/secp256k1@1.7.1", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" @@ -1148,11 +1143,6 @@ "@sentry/types" "5.30.0" tslib "^1.9.3" -"@sinclair/typebox@^0.32.20": - version "0.32.35" - resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.32.35.tgz#41c04473509478df9895800018a3d3ae7d40fb3c" - integrity sha512-Ul3YyOTU++to8cgNkttakC0dWvpERr6RYoHO2W47DLbFvrwBDJUY31B1sImH6JZSYc4Kt4PyHtoPNu+vL2r2dA== - "@sindresorhus/is@^4.0.0": version "4.6.0" resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" @@ -1388,21 +1378,6 @@ agent-base@^7.0.2, agent-base@^7.1.0: dependencies: debug "^4.3.4" -agent-twitter-client@^0.0.16: - version "0.0.16" - resolved "https://registry.npmjs.org/agent-twitter-client/-/agent-twitter-client-0.0.16.tgz#c800047b668c111d4d07c7fdcad3237a2a34f29f" - integrity sha512-Clgb/N2LXoGMlId6GDUaaR05eJ0PqSifM6wikl/FiQ2+3+6I2ZhZB7KRulc8R4xvYFe6h0wNWe6FZiF48r124w== - dependencies: - "@sinclair/typebox" "^0.32.20" - headers-polyfill "^3.1.2" - json-stable-stringify "^1.0.2" - node-fetch "^3.3.2" - otpauth "^9.2.2" - set-cookie-parser "^2.6.0" - tough-cookie "^4.1.2" - tslib "^2.5.2" - twitter-api-v2 "^1.18.2" - agentkeepalive@^4.2.1: version "4.5.0" resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" @@ -1939,17 +1914,6 @@ cacheable-request@^7.0.2: normalize-url "^6.0.1" responselike "^2.0.0" -call-bind@^1.0.5: - version "1.0.7" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" - integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== - dependencies: - es-define-property "^1.0.0" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - set-function-length "^1.2.1" - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -2339,11 +2303,6 @@ csstype@3.1.3, csstype@^3.1.3: resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -data-uri-to-buffer@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz#d8feb2b2881e6a4f58c2e08acfd0e2834e26222e" - integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== - dayjs@^1.11.11: version "1.11.11" resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e" @@ -2392,7 +2351,7 @@ defer-to-connect@^2.0.0: resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== -define-data-property@^1.0.1, define-data-property@^1.1.4: +define-data-property@^1.0.1: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -3008,14 +2967,6 @@ fecha@^4.2.0: resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd" integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== -fetch-blob@^3.1.2, fetch-blob@^3.1.4: - version "3.2.0" - resolved "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz#f09b8d4bbd45adc6f0c20b7e787e793e309dcce9" - integrity sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ== - dependencies: - node-domexception "^1.0.0" - web-streams-polyfill "^3.0.3" - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -3105,13 +3056,6 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -formdata-polyfill@^4.0.10: - version "4.0.10" - resolved "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" - integrity sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g== - dependencies: - fetch-blob "^3.1.2" - fp-ts@1.19.3: version "1.19.3" resolved "https://registry.yarnpkg.com/fp-ts/-/fp-ts-1.19.3.tgz#261a60d1088fbff01f91256f91d21d0caaaaa96f" @@ -3456,7 +3400,7 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: +has-property-descriptors@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== @@ -3507,11 +3451,6 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -headers-polyfill@^3.1.2: - version "3.3.0" - resolved "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-3.3.0.tgz#67c6ef7b72d4c8cac832ad5936f5b3a56e7b705a" - integrity sha512-5e57etwBpNcDc0b6KCVWEh/Ro063OxPvzVimUdM0/tsYM/T7Hfy3kknIGj78SFTOhNd8AZY41U8mOHoO4LzmIQ== - hmac-drbg@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -3771,11 +3710,6 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -3867,16 +3801,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== -json-stable-stringify@^1.0.2: - version "1.1.1" - resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz#52d4361b47d49168bcc4e564189a42e5a7439454" - integrity sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg== - dependencies: - call-bind "^1.0.5" - isarray "^2.0.5" - jsonify "^0.0.1" - object-keys "^1.1.1" - json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -3917,11 +3841,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonify@^0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" - integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== - jszip@^3.1.0: version "3.10.1" resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2" @@ -4471,11 +4390,6 @@ node-api-version@^0.2.0: dependencies: semver "^7.3.5" -node-domexception@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" - integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== - node-fetch@^2.6.12: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -4483,15 +4397,6 @@ node-fetch@^2.6.12: dependencies: whatwg-url "^5.0.0" -node-fetch@^3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz#d1e889bacdf733b4ff3b2b243eb7a12866a0b78b" - integrity sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA== - dependencies: - data-uri-to-buffer "^4.0.0" - fetch-blob "^3.1.4" - formdata-polyfill "^4.0.10" - node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: version "4.8.1" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.1.tgz#976d3ad905e71b76086f4f0b0d3637fe79b6cda5" @@ -4604,13 +4509,6 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -otpauth@^9.2.2: - version "9.3.5" - resolved "https://registry.npmjs.org/otpauth/-/otpauth-9.3.5.tgz#0a15e453549f521ecc93b67f5e57aa95fe3de991" - integrity sha512-jQyqOuQExeIl4YIiOUz4TdEcamgAgPX6UYeeS9Iit4lkvs7bwHb0JNDqchGRccbRfvWHV6oRwH36tOsVmc+7hQ== - dependencies: - "@noble/hashes" "1.5.0" - p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" @@ -4859,13 +4757,6 @@ ps-tree@^1.2.0: dependencies: event-stream "=3.3.4" -psl@^1.1.33: - version "1.15.0" - resolved "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6" - integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w== - dependencies: - punycode "^2.3.1" - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -4874,16 +4765,11 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: +punycode@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - queue-microtask@^1.2.2, queue-microtask@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -5333,11 +5219,6 @@ require-from-string@^2.0.0, require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - resedit@^1.7.0: version "1.7.2" resolved "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz#b1041170b99811710c13f949c7d225871de4cc78" @@ -5565,23 +5446,6 @@ set-blocking@^2.0.0: resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== -set-cookie-parser@^2.6.0: - version "2.7.1" - resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz#3016f150072202dfbe90fadee053573cc89d2943" - integrity sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ== - -set-function-length@^1.2.1: - version "1.2.2" - resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" - integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== - dependencies: - define-data-property "^1.1.4" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.4" - gopd "^1.0.1" - has-property-descriptors "^1.0.2" - setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -5970,16 +5834,6 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tough-cookie@^4.1.2: - version "4.1.4" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" - integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -6012,11 +5866,6 @@ tslib@^2.4.0, tslib@^2.6.2: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== -tslib@^2.5.2: - version "2.8.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" - integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== - tsort@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" @@ -6032,11 +5881,6 @@ tweetnacl@^1.0.3: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== -twitter-api-v2@^1.18.2: - version "1.18.2" - resolved "https://registry.npmjs.org/twitter-api-v2/-/twitter-api-v2-1.18.2.tgz#fd03d0ac4c7ed9f0d8f76786d5908d7aced3af78" - integrity sha512-ggImmoAeVgETYqrWeZy+nWnDpwgTP+IvFEc03Pitt1HcgMX+Yw17rP38Fb5FFTinuyNvS07EPtAfZ184uIyB0A== - type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -6110,11 +5954,6 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - universalify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" @@ -6149,14 +5988,6 @@ uri-js@^4.2.2, uri-js@^4.4.1: dependencies: punycode "^2.1.0" -url-parse@^1.5.3: - version "1.5.10" - resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - usehooks-ts@^2.14.0: version "2.16.0" resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-2.16.0.tgz#31deaa2f1147f65666aae925bd890b54e63b0d3f" @@ -6195,11 +6026,6 @@ wcwidth@^1.0.1: dependencies: defaults "^1.0.3" -web-streams-polyfill@^3.0.3: - version "3.3.3" - resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz#2073b91a2fdb1fbfbd401e7de0ac9f8214cecb4b" - integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" From 53513898cebada95f0c421618131dbe2dd6ba2ba Mon Sep 17 00:00:00 2001 From: Mohan Date: Thu, 29 May 2025 15:32:52 +0530 Subject: [PATCH 14/44] feat: more optimus features (#936) * feat: update feature flags to disable bridge onboarding and bridge add funds * feat: update hash for Optimus service template * fix: add optional chaining for monthly gas estimate retrieval * fix: update import statement for EvmChainName in AddFundsSection * feat: add agentFieldProps import to ModiusUpdateForm * feat: restore Optimism staking program IDs in enums * feat: add Optimism staking program IDs to activity checkers --- .../MainPage/sections/AddFundsSection.tsx | 2 +- .../UpdateAgentPage/ModiusUpdateForm.tsx | 1 + frontend/components/bridge/utils.ts | 2 +- frontend/config/activityCheckers.ts | 18 +-- frontend/config/stakingPrograms/optimism.ts | 116 +++++++++--------- frontend/constants/serviceTemplates.ts | 2 +- frontend/enums/StakingProgram.ts | 6 +- frontend/hooks/useFeatureFlag.ts | 2 + 8 files changed, 76 insertions(+), 73 deletions(-) diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index 178a58083..7121ccd7a 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -6,9 +6,9 @@ import { forwardRef, useCallback, useMemo, useRef, useState } from 'react'; import { CustomAlert } from '@/components/Alert'; import { SendFundAction } from '@/components/bridge/types'; import { CHAIN_CONFIG } from '@/config/chains'; +import { EvmChainName } from '@/constants/chains'; import { NA, UNICODE_SYMBOLS } from '@/constants/symbols'; import { SWAP_URL_BY_EVM_CHAIN } from '@/constants/urls'; -import { EvmChainName } from '@/enums/Chain'; import { Pages } from '@/enums/Pages'; import { useFeatureFlag } from '@/hooks/useFeatureFlag'; import { usePageState } from '@/hooks/usePageState'; diff --git a/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx b/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx index 02abf5aa3..98098739e 100644 --- a/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx +++ b/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx @@ -8,6 +8,7 @@ import { useServices } from '@/hooks/useServices'; import { Nullable } from '@/types/Util'; import { + agentFieldProps, requiredRules, validateApiKey, validateMessages, diff --git a/frontend/components/bridge/utils.ts b/frontend/components/bridge/utils.ts index ef28fc420..e4c045118 100644 --- a/frontend/components/bridge/utils.ts +++ b/frontend/components/bridge/utils.ts @@ -93,7 +93,7 @@ const useGetBridgeRequirementsParamsWithMonthlyGasEstimate = () => { const monthlyGasEstimate = SERVICE_TEMPLATES.find( (template) => template.home_chain === toMiddlewareChain, - )?.configurations[toMiddlewareChain].monthly_gas_estimate ?? 0; + )?.configurations[toMiddlewareChain]?.monthly_gas_estimate ?? 0; // amount = max(refill_requirement_masterSafe, monthly_gas_estimate) + refill_requirements_masterEOA const amount = diff --git a/frontend/config/activityCheckers.ts b/frontend/config/activityCheckers.ts index 0daf9a786..4a7af3f3d 100644 --- a/frontend/config/activityCheckers.ts +++ b/frontend/config/activityCheckers.ts @@ -120,15 +120,15 @@ export const OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS: Record< [STAKING_PROGRAM_IDS.OptimusAlpha1]: getStakingActivityCheckerContract( '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', ), - // [STAKING_PROGRAM_IDS.OptimusAlpha2]: getStakingActivityCheckerContract( - // '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', - // ), - // [STAKING_PROGRAM_IDS.OptimusAlpha3]: getStakingActivityCheckerContract( - // '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', - // ), - // [STAKING_PROGRAM_IDS.OptimusAlpha4]: getStakingActivityCheckerContract( - // '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', - // ), + [STAKING_PROGRAM_IDS.OptimusAlpha2]: getStakingActivityCheckerContract( + '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', + ), + [STAKING_PROGRAM_IDS.OptimusAlpha3]: getStakingActivityCheckerContract( + '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', + ), + [STAKING_PROGRAM_IDS.OptimusAlpha4]: getStakingActivityCheckerContract( + '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', + ), } as const; export const CELO_STAKING_PROGRAMS_ACTIVITY_CHECKERS: Record< diff --git a/frontend/config/stakingPrograms/optimism.ts b/frontend/config/stakingPrograms/optimism.ts index 4d91354b5..fe7756acd 100644 --- a/frontend/config/stakingPrograms/optimism.ts +++ b/frontend/config/stakingPrograms/optimism.ts @@ -19,12 +19,12 @@ export const OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record< > = { [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha1]: '0x88996bbdE7f982D93214881756840cE2c77C4992', - // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2]: - // '0xBCA056952D2A7a8dD4A002079219807CFDF9fd29', - // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3]: - // '0x0f69f35652B1acdbD769049334f1AC580927E139', - // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4]: - // '0x6891Cf116f9a3bDbD1e89413118eF81F69D298C3', + [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2]: + '0xBCA056952D2A7a8dD4A002079219807CFDF9fd29', + [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3]: + '0x0f69f35652B1acdbD769049334f1AC580927E139', + [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4]: + '0x6891Cf116f9a3bDbD1e89413118eF81F69D298C3', }; export const OPTIMISM_STAKING_PROGRAMS: { @@ -46,56 +46,56 @@ export const OPTIMISM_STAKING_PROGRAMS: { STAKING_TOKEN_PROXY_ABI, ), }, - // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2]: { - // chainId: EvmChainId.Optimism, - // name: 'Optimus Alpha II', - // agentsSupported: [AgentType.Optimus], - // stakingRequirements: { [TokenSymbol.OLAS]: 100 }, - // activityChecker: - // OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ - // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2 - // ], - // contract: new MulticallContract( - // OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ - // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2 - // ], - // STAKING_TOKEN_PROXY_ABI, - // ), - // }, - // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3]: { - // chainId: EvmChainId.Optimism, - // name: 'Optimus Alpha III', - // agentsSupported: [AgentType.Optimus], - // stakingRequirements: { - // [TokenSymbol.OLAS]: 1000, - // }, - // activityChecker: - // OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ - // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3 - // ], - // contract: new MulticallContract( - // OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ - // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3 - // ], - // STAKING_TOKEN_PROXY_ABI, - // ), - // }, - // [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4]: { - // chainId: EvmChainId.Optimism, - // name: 'Optimus Alpha IV', - // agentsSupported: [AgentType.Optimus], - // stakingRequirements: { - // [TokenSymbol.OLAS]: 5000, - // }, - // activityChecker: - // OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ - // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4 - // ], - // contract: new MulticallContract( - // OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ - // OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4 - // ], - // STAKING_TOKEN_PROXY_ABI, - // ), - // }, + [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2]: { + chainId: EvmChainId.Optimism, + name: 'Optimus Alpha II', + agentsSupported: [AgentType.Optimus], + stakingRequirements: { [TokenSymbol.OLAS]: 100 }, + activityChecker: + OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2 + ], + contract: new MulticallContract( + OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha2 + ], + STAKING_TOKEN_PROXY_ABI, + ), + }, + [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3]: { + chainId: EvmChainId.Optimism, + name: 'Optimus Alpha III', + agentsSupported: [AgentType.Optimus], + stakingRequirements: { + [TokenSymbol.OLAS]: 1000, + }, + activityChecker: + OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3 + ], + contract: new MulticallContract( + OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha3 + ], + STAKING_TOKEN_PROXY_ABI, + ), + }, + [OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4]: { + chainId: EvmChainId.Optimism, + name: 'Optimus Alpha IV', + agentsSupported: [AgentType.Optimus], + stakingRequirements: { + [TokenSymbol.OLAS]: 5000, + }, + activityChecker: + OPTIMISM_STAKING_PROGRAMS_ACTIVITY_CHECKERS[ + OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4 + ], + contract: new MulticallContract( + OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + OPTIMISM_STAKING_PROGRAM_IDS.OptimusAlpha4 + ], + STAKING_TOKEN_PROXY_ABI, + ), + }, }; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index bf9a907c2..8701fdb8c 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -416,7 +416,7 @@ export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { export const OPTIMUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Optimus, name: 'Optimus - Optimism', - hash: 'bafybeienicyxffuxlwcacwr3qfj4ijvaih4opziogwncs2japau6vzh4bu', + hash: 'bafybeidjtlrave3ck3usj3cr3wd6vjjipa7dhcoxv6manoqo6mayiyjuu4', description: 'Optimus service deployment on Optimism network', image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', diff --git a/frontend/enums/StakingProgram.ts b/frontend/enums/StakingProgram.ts index deafe2489..d8ab2005c 100644 --- a/frontend/enums/StakingProgram.ts +++ b/frontend/enums/StakingProgram.ts @@ -34,9 +34,9 @@ export type ModeStakingProgramId = ValueOf; export const OPTIMISM_STAKING_PROGRAM_IDS = { OptimusAlpha1: 'optimus_alpha', - // OptimusAlpha2: 'optimus_alpha_2', - // OptimusAlpha3: 'optimus_alpha_3', - // OptimusAlpha4: 'optimus_alpha_4', + OptimusAlpha2: 'optimus_alpha_2', + OptimusAlpha3: 'optimus_alpha_3', + OptimusAlpha4: 'optimus_alpha_4', } as const; export type OptimismStakingProgramId = ValueOf< diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index f60ece00d..20ee99929 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -93,6 +93,8 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': true, 'agent-settings': true, + 'bridge-onboarding': false, + 'bridge-add-funds': false, }, }); From 2bb0f30008eb0d77b2fc5c43aaf5cf94243777b8 Mon Sep 17 00:00:00 2001 From: Mohan Date: Thu, 29 May 2025 16:14:29 +0530 Subject: [PATCH 15/44] feat: update agent profile handling for Modius and Optimus (#941) --- .../components/YourWalletPage/AgentTitle.tsx | 32 +++++++++++++++---- frontend/types/ElectronApi.ts | 6 ++-- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/frontend/components/YourWalletPage/AgentTitle.tsx b/frontend/components/YourWalletPage/AgentTitle.tsx index 1a033cf82..e240490fd 100644 --- a/frontend/components/YourWalletPage/AgentTitle.tsx +++ b/frontend/components/YourWalletPage/AgentTitle.tsx @@ -40,7 +40,7 @@ const ExternalAgentProfileLink = ({ href }: { href: string }) => { ); }; -const ModiusAgentProfile = ({ onClick }: { onClick: () => void }) => { +const PortfolioAndChatUi = ({ onClick }: { onClick: () => void }) => { const electronApi = useElectronApi(); const { storeState } = useStore(); const { selectedService, selectedAgentType } = useServices(); @@ -53,8 +53,14 @@ const ModiusAgentProfile = ({ onClick }: { onClick: () => void }) => { const canAccessProfile = useMemo(() => { if (!storeState) return false; - return storeState.modius?.isProfileWarningDisplayed ?? false; - }, [storeState]); + if (selectedAgentType === AgentType.Modius) { + return storeState.modius?.isProfileWarningDisplayed ?? false; + } + if (selectedAgentType === AgentType.Optimus) { + return storeState.optimus?.isProfileWarningDisplayed ?? false; + } + return false; + }, [storeState, selectedAgentType]); const handleAgentProfileClick = useCallback(() => { if (!!geminiApiKey || canAccessProfile) { @@ -84,6 +90,12 @@ const ModiusAgentProfile = ({ onClick }: { onClick: () => void }) => { onClick(); }, [dontShowAgain, handleDoNotShowAgain, onClick]); + const agentName = useMemo(() => { + if (selectedAgentType === AgentType.Modius) return 'Modius'; + if (selectedAgentType === AgentType.Optimus) return 'Optimus'; + return NA; + }, [selectedAgentType]); + return ( <> @@ -98,8 +110,8 @@ const ModiusAgentProfile = ({ onClick }: { onClick: () => void }) => { >
      - To unlock the full functionality of Modius profile, a Gemini API key - is required. You can get a free Gemini API key through the{' '} + To unlock the full functionality of {agentName} profile, a Gemini + API key is required. You can get a free Gemini API key through the{' '} Google AI Studio @@ -187,7 +199,15 @@ export const AgentTitle = ({ address }: { address: Address }) => { middlewareChain === MiddlewareChain.MODE && selectedAgentType === AgentType.Modius ) { - return ; + return ; + } + + // optimism - optimus + if ( + middlewareChain === MiddlewareChain.OPTIMISM && + selectedAgentType === AgentType.Optimus + ) { + return ; } return null; diff --git a/frontend/types/ElectronApi.ts b/frontend/types/ElectronApi.ts index 15bca15c6..2de1e5d7b 100644 --- a/frontend/types/ElectronApi.ts +++ b/frontend/types/ElectronApi.ts @@ -17,11 +17,13 @@ export type ElectronStore = { // Each agent has its own settings [AgentType.PredictTrader]?: AgentSettings; [AgentType.Memeooorr]?: AgentSettings; + [AgentType.AgentsFunCelo]?: AgentSettings; [AgentType.Modius]?: AgentSettings & { isProfileWarningDisplayed: boolean; }; - [AgentType.AgentsFunCelo]?: AgentSettings; - [AgentType.Optimus]?: AgentSettings; + [AgentType.Optimus]?: AgentSettings & { + isProfileWarningDisplayed: boolean; + }; }; export type ElectronTrayIconStatus = From 339abc6779cedbd18dd429d2a089a30db62efbb3 Mon Sep 17 00:00:00 2001 From: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Date: Thu, 29 May 2025 19:30:51 +0530 Subject: [PATCH 16/44] feat: update olas-operate-middleware reference to latest commit (#942) Signed-off-by: OjusWiZard --- poetry.lock | 6 +++--- pyproject.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index bfd51dce0..c0b981bf8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2351,8 +2351,8 @@ web3 = "==6.1.0" [package.source] type = "git" url = "https://github.com/valory-xyz/olas-operate-middleware.git" -reference = "920957b1871a533a3a63f1162d9c6d10625226a8" -resolved_reference = "920957b1871a533a3a63f1162d9c6d10625226a8" +reference = "b89441b26112ffd6b50336d9e4a987778d5b55c2" +resolved_reference = "b89441b26112ffd6b50336d9e4a987778d5b55c2" [[package]] name = "open-aea" @@ -4058,4 +4058,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "ee0d3ab758d5e2dfc4e0e984b7064f301bb3dd800b9a82a39358d4375a1e3c8e" +content-hash = "ec523d803cd8d17245d1f07b3e55ed04154f951a80d7c09ef818930faa450a06" diff --git a/pyproject.toml b/pyproject.toml index 60848d481..a92bad4d6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,7 @@ include = [] [tool.poetry.dependencies] python = ">=3.9,<3.12" -olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "920957b1871a533a3a63f1162d9c6d10625226a8"} +olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "b89441b26112ffd6b50336d9e4a987778d5b55c2"} [build-system] requires = ["poetry-core"] From c51c2ac8eb88c34d9d64c206fd4edf618a662ae0 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Thu, 29 May 2025 19:49:12 +0530 Subject: [PATCH 17/44] feat: add .scripts/ to .gitignore for development scripts --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index fde33a2cf..7f9e0fcde 100644 --- a/.gitignore +++ b/.gitignore @@ -51,4 +51,5 @@ leak_report *.log # custom script for development +.scripts/ custom-script.sh From 86b6f366ab5bbbbc3b29947688116f60904090a7 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Fri, 30 May 2025 00:27:02 +0530 Subject: [PATCH 18/44] feat: update hash for Optimus service template --- frontend/constants/serviceTemplates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 8701fdb8c..c4a01684f 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -416,7 +416,7 @@ export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { export const OPTIMUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Optimus, name: 'Optimus - Optimism', - hash: 'bafybeidjtlrave3ck3usj3cr3wd6vjjipa7dhcoxv6manoqo6mayiyjuu4', + hash: 'bafybeibhbikzzsptbjvix4qwjp32a7az4ytrs5a7mw2dd5s2sr43phg3s4', description: 'Optimus service deployment on Optimism network', image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', From c2171c9300db88b3de8e12d49bd9545faa56e0f7 Mon Sep 17 00:00:00 2001 From: Mohan Date: Fri, 30 May 2025 13:51:00 +0530 Subject: [PATCH 19/44] feat: staging to main (#933) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) * feat: modius hash update (#916) * fix: update hash for Modius service template * fix: update hash for Modius service template * fix: update hash for Modius service template * feat: staging to main (#913) (#919) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts --------- * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- * release: 0.2.0-rc270 * chore: update middleware --------- * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) --------- Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory * fix: update hash for Trader Agent service template (#921) * fix: update comment for Trader Agent name uniqueness * feat: FE implementation of New Agents.fun setup integration (#907) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware * feat: memeooorr consolidate form (#904) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * feat: memeooorr add new fields to form (#905) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * refactor: remove Twitter validation logic and associated types from Memeooorr agent form * chore: add TODO comments for product clarification in YourAgentCannotSignIn and AgentTitle components * feat: refactor Memeooorr agent form and related components to integrate new API keys and remove deprecated fields * feat: update Memeooorr agent form and setup components for improved API token handling and styling * feat: refactor Memeooorr agent form and validation logic to enhance API token handling and streamline component imports * feat: update Memeooorr agent form and types to include XCredentialsKeys and enhance service description handling * feat: remove Twitter login validation and related dependencies from the application * feat: remove YourAgentCannotSignIn component and related imports from AlertSections * feat: add X username field to Memeooorr agent form and update related components * feat: update Memeooorr agent form and related components to include X username handling * feat: Update agent setup and show alert (#908) * feat: add UpdateAgentConfiguration component to alert sections * feat: remove healthcheck alert state and related logic from SharedProvider * feat: implement isMemeooorrFieldUpdateCompleted check for agent deployment and alert visibility * feat: add MemeooorrUpdateSetup component and update routing in UpdateAgentPage * feat: update loading text style to fit content and add fit-content class * feat: add clarification comments for Memeooorr agent configuration requirements * chore: bump middleware (#909) Signed-off-by: OjusWiZard * feat: update service template hash and version for Memeooorr agent * fix: add `tweepy` dependency Signed-off-by: OjusWiZard * fix: show alert on agent settings (#911) * feat: add showTokensRequiredMessage prop to XAccountApiTokens and display alert * feat: update MemeooorrAgentForm to use agentFormType prop for variant handling * fix: update hash and service version for AGENTS_FUN_COMMON_TEMPLATE --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * fix: update version to 0.2.0-rc173 in package.json and pyproject.toml * fix: update service template hashes and version for Trader and Optimus agents (#926) * fix: update version to 0.2.0-rc174 in package.json and pyproject.toml * feat: update middleware (#929) * fix: update coverage and typing-inspection versions in poetry.lock and pyproject.toml * fix: update pluggy, pycryptodome, and setuptools versions in poetry.lock * chore: update middleware: bridging, but NOT split-binaries --------- Co-authored-by: jmoreira-valory * fix: update version to 0.2.0-rc175 in package.json and pyproject.toml * chore: fix poetry deps * feat: staging-ea to staging (#925) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware * feat: modius bridging (#915) * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: enable modius bridging (#914) * feat: update ETHEREUM_TOKEN_CONFIG to include USDC and enable bridge onboarding feature * fix: update fund requirements structure and adjust values for testing * fix: update chain name in BridgingSteps component to use dynamic value * fix: refactor logic for mapping bridge total requirements to improve readability * fix: update fund requirements for MODIUS_SERVICE_TEMPLATE to correct values * feat: modius bridge add alert (#918) * fix: update funding message to include dynamic chain name * feat: enhance BridgeOnEvm with CustomAlert and layout adjustments * feat: update address type usage in agents and service modules (#922) * feat: modius bridge safe creation update (#924) * feat: enforce transfer of excess assets during safe creation * feat: enhance FundsAreSafeMessage with additional retry suggestion * feat: improve bridge retry logic and user feedback * feat: update success message for bridge completion --------- Co-authored-by: jmoreira-valory * chore: update middleware * chore: update staging-ea with staging (#928) * feat: staging to main (#920) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) * feat: modius hash update (#916) * fix: update hash for Modius service template * fix: update hash for Modius service template * fix: update hash for Modius service template * feat: staging to main (#913) (#919) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts --------- * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- * release: 0.2.0-rc270 * chore: update middleware --------- * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) --------- Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory * fix: update hash for Trader Agent service template (#921) * fix: update comment for Trader Agent name uniqueness * feat: FE implementation of New Agents.fun setup integration (#907) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and… * (feat) OPE-117: Updates the description in service template to distinguish Pearl services from QS (#931) * fix: update service template descriptions to include [Pearl service] and clarify uniqueness requirement for names * fix: enhance KPI description handling by introducing KPI_DESC_PREFIX and updating service descriptions * chore: hash updates (#934) * fix: update service template hashes for AGENTS_FUN_COMMON_TEMPLATE and MODIUS_SERVICE_TEMPLATE * feat: prepend KPI_DESC_PREFIX to Optimus service description * chore: update version to 0.2.0-rc176 in package.json and pyproject.toml * chore: update value for Tools accuracy hash in PREDICT_SERVICE_TEMPLATE (#940) --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard --- frontend/client/types.ts | 12 ++-- .../BridgeInProgress/BridgeInProgress.tsx | 15 ++-- .../useMasterSafeCreationAndTransfer.ts | 1 - .../BridgeInProgress/useRetryBridge.ts | 13 +++- .../SetupBridgeOnboarding/BridgeOnEvm.tsx | 37 +++++++--- .../SetupPage/Create/SetupEoaFunding.tsx | 4 +- frontend/components/bridge/BridgingSteps.tsx | 7 +- .../components/bridge/DepositForBridging.tsx | 69 +++++++++---------- frontend/config/agents.ts | 3 +- frontend/config/tokens.ts | 6 ++ frontend/constants/serviceTemplates.ts | 24 ++++--- frontend/hooks/useFeatureFlag.ts | 2 +- frontend/service/Wallet.ts | 3 +- frontend/styles/globals.scss | 5 +- frontend/utils/service.ts | 15 +++- package.json | 2 +- pyproject.toml | 2 +- 17 files changed, 137 insertions(+), 83 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index ec5d3732d..f867c32e6 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -76,7 +76,7 @@ export type MiddlewareServiceResponse = { export type ServiceTemplate = { agentType: AgentType; - name: string; + name: string; // Should be unique across all services hash: string; description: string; image: string; @@ -99,15 +99,13 @@ export type ConfigurationTemplate = { monthly_gas_estimate: number; fund_requirements: { // zero address means native currency - [tokenAddress: string]: FundRequirementsTemplate; + [tokenAddress: Address]: { + agent: number; + safe: number; + }; }; }; -export type FundRequirementsTemplate = { - agent: number; - safe: number; -}; - export type DeployedNodes = { agent: string[]; tendermint: string[]; diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx index 3780b572a..2218f745f 100644 --- a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress/BridgeInProgress.tsx @@ -1,5 +1,5 @@ import { Typography } from 'antd'; -import { useCallback, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { CustomAlert } from '@/components/Alert'; import { BridgeTransferFlow } from '@/components/bridge/BridgeTransferFlow'; @@ -63,6 +63,7 @@ export const BridgeInProgress = ({ const { goto } = usePageState(); const symbols = transfers.map((transfer) => transfer.toSymbol); + const [isBridgeRetrying, setIsBridgeRetrying] = useState(false); const refetchBridgeExecute = useRetryBridge(); const { isBridging, isBridgingFailed, isBridgingCompleted, bridgeStatus } = @@ -136,9 +137,12 @@ export const BridgeInProgress = ({ ]); const onBridgeFailRetry = useCallback(() => { + setIsBridgeRetrying(true); refetchBridgeExecute((e: Nullable) => onBridgeRetryOutcome(e), - ); + ).finally(() => { + setIsBridgeRetrying(false); + }); }, [refetchBridgeExecute, onBridgeRetryOutcome]); const bridgeDetails = useMemo(() => { @@ -157,7 +161,9 @@ export const BridgeInProgress = ({ subSteps: (bridgeStatus || []).map((step) => ({ ...step, onRetry: onBridgeFailRetry, - onRetryProps: { isLoading: currentBridgeStatus === 'process' }, + onRetryProps: { + isLoading: currentBridgeStatus === 'process' || isBridgeRetrying, + }, })) satisfies StepEvent[], }; }, [ @@ -166,6 +172,7 @@ export const BridgeInProgress = ({ isBridgingFailed, isBridgingCompleted, bridgeStatus, + isBridgeRetrying, onBridgeFailRetry, ]); @@ -242,7 +249,7 @@ export const BridgeInProgress = ({ /> {!!bridgeDetails && ( { if (!refetch) return; const { data } = await refetch(); - onRetryOutcome(data?.is_refill_required ? 'NEED_REFILL' : null); + if (!data) return; + + if (data?.is_refill_required) { + onRetryOutcome('NEED_REFILL'); + } else { + message.open({ + icon: null, + content: + "Bridging complete! Please restart the app if you're not redirected automatically.", + }); + } }, [refetch], ); diff --git a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx index a80e61cee..4f5d9e629 100644 --- a/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx +++ b/frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeOnEvm.tsx @@ -1,5 +1,6 @@ -import { Typography } from 'antd'; +import { Flex, Typography } from 'antd'; +import { CustomAlert } from '@/components/Alert'; import { DepositForBridging } from '@/components/bridge/DepositForBridging'; import { CardFlex } from '@/components/styled/CardFlex'; import { CardSection } from '@/components/styled/CardSection'; @@ -27,14 +28,32 @@ export const BridgeOnEvm = ({ - - - Bridge from {FROM_CHAIN_NAME} - - - The bridged amount covers all funds required to create your account - and run your agent, including fees. No further funds will be needed. - + + + + Bridge from {FROM_CHAIN_NAME} + + + The bridged amount covers all funds required to create your account + and run your agent, including fees. No further funds will be needed. + + + + + + Only send funds on Ethereum! + + Full amount of funds is required to initiate the bridging. + + + } + /> + ( <> - Send funds on Base to create your account. Additional funds for staking - and operating your agent will be requested separately. + Send funds on {chainName} to create your account. Additional funds for + staking and operating your agent will be requested separately. diff --git a/frontend/components/bridge/BridgingSteps.tsx b/frontend/components/bridge/BridgingSteps.tsx index 321c84999..5e7bbcafb 100644 --- a/frontend/components/bridge/BridgingSteps.tsx +++ b/frontend/components/bridge/BridgingSteps.tsx @@ -1,6 +1,5 @@ import { LoadingOutlined } from '@ant-design/icons'; import { Button, Flex, Steps, Typography } from 'antd'; -import { noop } from 'lodash'; import React, { useMemo } from 'react'; import styled from 'styled-components'; @@ -34,7 +33,7 @@ const TxnDetails = ({ link }: { link: string }) => ( type FundsAreSafeMessageProps = Pick; const FundsAreSafeMessage = ({ - onRetry = noop, + onRetry, onRetryProps, }: FundsAreSafeMessageProps) => ( @@ -64,6 +63,10 @@ const FundsAreSafeMessage = ({ the Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + You can also try restarting the app! + ); diff --git a/frontend/components/bridge/DepositForBridging.tsx b/frontend/components/bridge/DepositForBridging.tsx index 6ac8fd552..29862dd9b 100644 --- a/frontend/components/bridge/DepositForBridging.tsx +++ b/frontend/components/bridge/DepositForBridging.tsx @@ -187,41 +187,40 @@ export const DepositForBridging = ({ if (!bridgeTotalRequirements || !bridgeRefillRequirements) return []; - return Object.entries(bridgeTotalRequirements).map( - ([tokenAddress, totalRequired]) => { - const totalRequiredInWei = BigInt(totalRequired); - - // current balance = total_required_amount - required_amount - // eg. if total_required_amount = 1000 and required_amount = 200, - // then the assumed current_balance = 1000 - 200 = 800 - const currentBalanceInWei = - totalRequiredInWei - - BigInt(bridgeRefillRequirements[tokenAddress as Address] || 0); - - const token = Object.values(ETHEREUM_TOKEN_CONFIG).find((tokenInfo) => { - if (tokenAddress === AddressZero && !tokenInfo.address) return true; - return areAddressesEqual(tokenInfo.address!, tokenAddress); - }); - - if (!token) { - throw new Error( - `Failed to get the token info for the following token address: ${tokenAddress}`, - ); - } - - const areFundsReceived = totalRequiredInWei - currentBalanceInWei <= 0; - - return { - address: tokenAddress as Address, - symbol: token.symbol, - totalRequiredInWei, - currentBalanceInWei, - areFundsReceived, - decimals: token.decimals, - isNative: token.tokenType === TokenType.NativeGas, - } satisfies DepositTokenDetails; - }, - ); + const totalRequirements = Object.entries(bridgeTotalRequirements); + return totalRequirements.map(([tokenAddress, totalRequired]) => { + const totalRequiredInWei = BigInt(totalRequired); + + // current balance = total_required_amount - required_amount + // eg. if total_required_amount = 1000 and required_amount = 200, + // then the assumed current_balance = 1000 - 200 = 800 + const currentBalanceInWei = + totalRequiredInWei - + BigInt(bridgeRefillRequirements[tokenAddress as Address] || 0); + + const token = Object.values(ETHEREUM_TOKEN_CONFIG).find((tokenInfo) => { + if (tokenAddress === AddressZero && !tokenInfo.address) return true; + return areAddressesEqual(tokenInfo.address!, tokenAddress); + }); + + if (!token) { + throw new Error( + `Failed to get the token info for the following token address: ${tokenAddress}`, + ); + } + + const areFundsReceived = totalRequiredInWei - currentBalanceInWei <= 0; + + return { + address: tokenAddress as Address, + symbol: token.symbol, + totalRequiredInWei, + currentBalanceInWei, + areFundsReceived, + decimals: token.decimals, + isNative: token.tokenType === TokenType.NativeGas, + } satisfies DepositTokenDetails; + }); }, [bridgeFundingRequirements, masterEoa]); // After the user has deposited the required funds, diff --git a/frontend/config/agents.ts b/frontend/config/agents.ts index 74638fee9..d69eacd37 100644 --- a/frontend/config/agents.ts +++ b/frontend/config/agents.ts @@ -8,6 +8,7 @@ import { TokenSymbol } from '@/enums/Token'; import { AgentsFunBaseService } from '@/service/agents/AgentsFunBase'; import { ModiusService } from '@/service/agents/Modius'; import { PredictTraderService } from '@/service/agents/PredictTrader'; +import { Address } from '@/types/Address'; import { AgentConfig } from '@/types/Agent'; import { MODE_TOKEN_CONFIG } from './tokens'; @@ -17,7 +18,7 @@ const modiusFundRequirements = .fund_requirements; const modiusUsdcConfig = modiusFundRequirements?.[ - MODE_TOKEN_CONFIG[TokenSymbol.USDC].address as string + MODE_TOKEN_CONFIG[TokenSymbol.USDC].address as Address ]; export const AGENT_CONFIG: { diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index 8d4cb44c2..75d222dc5 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -54,6 +54,12 @@ export const ETHEREUM_TOKEN_CONFIG: ChainTokenConfig = { tokenType: TokenType.Erc20, symbol: TokenSymbol.OLAS, }, + [TokenSymbol.USDC]: { + address: '0xA0b86991c6218b36c1d19D4a2e9EB0CE3606EB48', + decimals: 6, + tokenType: TokenType.Erc20, + symbol: TokenSymbol.USDC, + }, } as const; const GNOSIS_TOKEN_CONFIG: ChainTokenConfig = { diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index da50b2442..eb0d3729a 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -7,11 +7,17 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { parseEther, parseUnits } from '@/utils/numberFormatters'; +/** + * Prefix for KPI description in service templates. + * This is used track services that are part of the Pearl service suite. + */ +export const KPI_DESC_PREFIX = '[Pearl service]'; + export const PREDICT_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.PredictTrader, // TODO: remove if causes errors on middleware name: 'Trader Agent', // should be unique across all services and not be updated hash: 'bafybeihe7r2a2vnbbqrzczlzjhhmzypxbre3gobupc65w4ea266hmk5efu', - description: 'Trader agent for omen prediction markets', + description: `${KPI_DESC_PREFIX} Trader agent for omen prediction markets`, image: 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', service_version: 'v0.25.5', @@ -83,7 +89,7 @@ export const PREDICT_SERVICE_TEMPLATE: ServiceTemplate = { name: 'Tools accuracy hash', description: '', // Use the latest value from https://github.com/valory-xyz/quickstart/blob/main/configs/config_predict_trader.json#L74 - value: 'QmTzMoaEtSRdAnVxpziXVNwqYcE6HVZpGs6TM8vhWw1HPt', + value: 'QmSJ9CRvEjwsQCckMG9NXtxkQrtmmgnjpxfnTLoA1jQsUm', provision_type: EnvProvisionType.FIXED, }, MECH_INTERACT_ROUND_TIMEOUT_SECONDS: { @@ -99,10 +105,10 @@ const AGENTS_FUN_COMMON_TEMPLATE: Pick< ServiceTemplate, 'env_variables' | 'hash' | 'image' | 'description' | 'service_version' > = { - hash: 'bafybeiajnpysvflxlbsynl4ybsdhgbbrx5hdjvzzdsxnbb6ejia4mrdmdi', + hash: 'bafybeiaymgtbsxf6zyoedpgocdjqd5qfnyr3ugybwo7u3iqyiseti4bzke', image: 'https://gateway.autonolas.tech/ipfs/QmQYDGMg8m91QQkTWSSmANs5tZwKrmvUCawXZfXVVWQPcu', - description: 'Memeooorr @twitter_handle', // should be overwritten with twitter username + description: `${KPI_DESC_PREFIX} Memeooorr @twitter_handle`, // NOTE: @twitter_handle to be replaced with twitter username service_version: 'v0.5.0-alpha3', env_variables: { BASE_LEDGER_RPC: { @@ -210,7 +216,7 @@ const AGENTS_FUN_COMMON_TEMPLATE: Pick< */ export const AGENTS_FUN_BASE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Memeooorr, - name: 'Memeooorr', // Should be unique across all services and not be updated + name: 'Memeooorr', home_chain: MiddlewareChain.BASE, configurations: { [MiddlewareChain.BASE]: { @@ -239,7 +245,7 @@ export const AGENTS_FUN_BASE_TEMPLATE: ServiceTemplate = { */ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = { agentType: AgentType.AgentsFunCelo, - name: 'Memeooorr - Celo', // Should be unique across all services and not be updated + name: 'Memeooorr - Celo', home_chain: MiddlewareChain.CELO, configurations: { [MiddlewareChain.CELO]: { @@ -264,9 +270,9 @@ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = { export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Modius, - name: 'Optimus', // Should be unique across all services and not be updated - hash: 'bafybeicxflz5lzklgc522zytvwi4rgycghdqdmzgkxojnjatommr7qvqfm', - description: 'Optimus', + name: 'Optimus', + hash: 'bafybeidjtlrave3ck3usj3cr3wd6vjjipa7dhcoxv6manoqo6mayiyjuu4', + description: `${KPI_DESC_PREFIX} Optimus`, image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', service_version: 'v0.3.15', diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index 0cc1b4792..c18b79055 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -80,7 +80,7 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': false, // temporarily hidden until mode is available on safe https://app.safe.global/new-safe/create 'agent-settings': true, - 'bridge-onboarding': false, + 'bridge-onboarding': true, 'bridge-add-funds': false, }, }); diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index 13f750232..f84ca69bc 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -30,12 +30,11 @@ const createEoa = async () => const createSafe = async ( chain: MiddlewareChain, backup_owner?: string, - transfer_excess_assets?: boolean, ): Promise => fetch(`${BACKEND_URL}/wallet/safe`, { method: 'POST', headers: { ...CONTENT_TYPE_JSON_UTF8 }, - body: JSON.stringify({ chain, backup_owner, transfer_excess_assets }), + body: JSON.stringify({ chain, backup_owner, transfer_excess_assets: true }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create safe'); diff --git a/frontend/styles/globals.scss b/frontend/styles/globals.scss index c10befc87..bbd893ec2 100644 --- a/frontend/styles/globals.scss +++ b/frontend/styles/globals.scss @@ -256,6 +256,7 @@ textarea, .text-center { text-align: center !important; } + .text-right { text-align: right !important; } @@ -313,10 +314,6 @@ ul.alert-list { max-width: 200px; } -.fit-content { - width: fit-content; -} - .loading-ellipses { display: inline-block; position: relative; /* Ensures absolute positioned :after is placed relative to this */ diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index b72c3a94a..d4ceec592 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -1,10 +1,14 @@ import { isEmpty, isNil } from 'lodash'; import { EnvProvisionType, ServiceTemplate } from '@/client'; -import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; +import { + KPI_DESC_PREFIX, + SERVICE_TEMPLATES, +} from '@/constants/serviceTemplates'; import { AgentType } from '@/enums/Agent'; import { StakingProgramId } from '@/enums/StakingProgram'; import { ServicesService } from '@/service/Services'; +import { Address } from '@/types/Address'; import { Service } from '@/types/Service'; import { DeepPartial } from '@/types/Util'; @@ -34,6 +38,11 @@ export const updateServiceIfNeeded = async ( partialServiceTemplate.name = serviceTemplate.name; } + // If the description doesn't include "[Pearl service]" then update it + if (!service.description.includes(KPI_DESC_PREFIX)) { + partialServiceTemplate.description = `${KPI_DESC_PREFIX} ${service.description}`; + } + // Check if there's a need to update or add env variables const envVariablesToUpdate: ServiceTemplate['env_variables'] = {}; Object.entries(serviceTemplate.env_variables).forEach( @@ -75,8 +84,8 @@ export const updateServiceIfNeeded = async ( if ( Object.entries(serviceHomeChainFundRequirements).some(([key, item]) => { return ( - templateFundRequirements[key].agent !== item.agent || - templateFundRequirements[key].safe !== item.safe + templateFundRequirements[key as Address].agent !== item.agent || + templateFundRequirements[key as Address].safe !== item.safe ); }) ) { diff --git a/package.json b/package.json index 47c7e3549..6b550c6cf 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "start:frontend": "cd frontend && yarn start", "test:frontend": "cd frontend && yarn test" }, - "version": "0.2.0-rc175", + "version": "0.2.0-rc176", "engine": { "node": ">=20", "yarn": ">=1.22.0", diff --git a/pyproject.toml b/pyproject.toml index 59bdda1cd..7dc50118e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-app" -version = "0.2.0-rc175" +version = "0.2.0-rc176" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From bdc8ea6900260ed021bd84777b6233f7f0b6ae95 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Fri, 30 May 2025 14:14:21 +0530 Subject: [PATCH 20/44] feat: update hash for Optimus service template --- frontend/constants/serviceTemplates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index c4a01684f..31859ce2f 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -416,7 +416,7 @@ export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { export const OPTIMUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Optimus, name: 'Optimus - Optimism', - hash: 'bafybeibhbikzzsptbjvix4qwjp32a7az4ytrs5a7mw2dd5s2sr43phg3s4', + hash: 'bafybeicumxyzmrvqzunupg6unx7geabzuw2tskhoa6wgk4cb6gv2rp5dqq', description: 'Optimus service deployment on Optimism network', image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', From 4288415226091322a14fb0c3a5181b70b5eafb46 Mon Sep 17 00:00:00 2001 From: Mohan Date: Fri, 30 May 2025 19:32:59 +0530 Subject: [PATCH 21/44] chore: update optimus branch with main (#944) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: staging to main (#920) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) * feat: modius hash update (#916) * fix: update hash for Modius service template * fix: update hash for Modius service template * fix: update hash for Modius service template * feat: staging to main (#913) (#919) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts --------- * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- * release: 0.2.0-rc270 * chore: update middleware --------- * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) --------- Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory * fix: update hash for Trader Agent service template (#921) * fix: update comment for Trader Agent name uniqueness * feat: FE implementation of New Agents.fun setup integration (#907) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware * feat: memeooorr consolidate form (#904) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * feat: memeooorr add new fields to form (#905) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * refactor: remove Twitter validation logic and associated types from Memeooorr agent form * chore: add TODO comments for product clarification in YourAgentCannotSignIn and AgentTitle components * feat: refactor Memeooorr agent form and related components to integrate new API keys and remove deprecated fields * feat: update Memeooorr agent form and setup components for improved API token handling and styling * feat: refactor Memeooorr agent form and validation logic to enhance API token handling and streamline component imports * feat: update Memeooorr agent form and types to include XCredentialsKeys and enhance service description handling * feat: remove Twitter login validation and related dependencies from the application * feat: remove YourAgentCannotSignIn component and related imports from AlertSections * feat: add X username field to Memeooorr agent form and update related components * feat: update Memeooorr agent form and related components to include X username handling * feat: Update agent setup and show alert (#908) * feat: add UpdateAgentConfiguration component to alert sections * feat: remove healthcheck alert state and related logic from SharedProvider * feat: implement isMemeooorrFieldUpdateCompleted check for agent deployment and alert visibility * feat: add MemeooorrUpdateSetup component and update routing in UpdateAgentPage * feat: update loading text style to fit content and add fit-content class * feat: add clarification comments for Memeooorr agent configuration requirements * chore: bump middleware (#909) Signed-off-by: OjusWiZard * feat: update service template hash and version for Memeooorr agent * fix: add `tweepy` dependency Signed-off-by: OjusWiZard * fix: show alert on agent settings (#911) * feat: add showTokensRequiredMessage prop to XAccountApiTokens and display alert * feat: update MemeooorrAgentForm to use agentFormType prop for variant handling * fix: update hash and service version for AGENTS_FUN_COMMON_TEMPLATE --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * fix: update version to 0.2.0-rc173 in package.json and pyproject.toml --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * feat: staging to main (#927) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) * feat: modius hash update (#916) * fix: update hash for Modius service template * fix: update hash for Modius service template * fix: update hash for Modius service template * feat: staging to main (#913) (#919) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts --------- * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- * release: 0.2.0-rc270 * chore: update middleware --------- * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) --------- Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory * fix: update hash for Trader Agent service template (#921) * fix: update comment for Trader Agent name uniqueness * feat: FE implementation of New Agents.fun setup integration (#907) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware * feat: memeooorr consolidate form (#904) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * feat: memeooorr add new fields to form (#905) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * refactor: remove Twitter validation logic and associated types from Memeooorr agent form * chore: add TODO comments for product clarification in YourAgentCannotSignIn and AgentTitle components * feat: refactor Memeooorr agent form and related components to integrate new API keys and remove deprecated fields * feat: update Memeooorr agent form and setup components for improved API token handling and styling * feat: refactor Memeooorr agent form and validation logic to enhance API token handling and streamline component imports * feat: update Memeooorr agent form and types to include XCredentialsKeys and enhance service description handling * feat: remove Twitter login validation and related dependencies from the application * feat: remove YourAgentCannotSignIn component and related imports from AlertSections * feat: add X username field to Memeooorr agent form and update related components * feat: update Memeooorr agent form and related components to include X username handling * feat: Update agent setup and show alert (#908) * feat: add UpdateAgentConfiguration component to alert sections * feat: remove healthcheck alert state and related logic from SharedProvider * feat: implement isMemeooorrFieldUpdateCompleted check for agent deployment and alert visibility * feat: add MemeooorrUpdateSetup component and update routing in UpdateAgentPage * feat: update loading text style to fit content and add fit-content class * feat: add clarification comments for Memeooorr agent configuration requirements * chore: bump middleware (#909) Signed-off-by: OjusWiZard * feat: update service template hash and version for Memeooorr agent * fix: add `tweepy` dependency Signed-off-by: OjusWiZard * fix: show alert on agent settings (#911) * feat: add showTokensRequiredMessage prop to XAccountApiTokens and display alert * feat: update MemeooorrAgentForm to use agentFormType prop for variant handling * fix: update hash and service version for AGENTS_FUN_COMMON_TEMPLATE --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * fix: update version to 0.2.0-rc173 in package.json and pyproject.toml * fix: update service template hashes and version for Trader and Optimus agents (#926) * fix: update version to 0.2.0-rc174 in package.json and pyproject.toml --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * feat: staging to main (#932) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) * feat: modius hash update (#916) * fix: update hash for Modius service template * fix: update hash for Modius service template * fix: update hash for Modius service template * feat: staging to main (#913) (#919) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts --------- * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- * release: 0.2.0-rc270 * chore: update middleware --------- * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) --------- Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory * fix: update hash for Trader Agent service template (#921) * fix: update comment for Trader Agent name uniqueness * feat: FE implementation of New Agents.fun setup integration (#907) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware * feat: memeooorr consolidate form (#904) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * feat: memeooorr add new fields to form (#905) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * refactor: remove Twitter validation logic and associated types from Memeooorr agent form * chore: add TODO comments for product clarification in YourAgentCannotSignIn and AgentTitle components * feat: refactor Memeooorr agent form and related components to integrate new API keys and remove deprecated fields * feat: update Memeooorr agent form and setup components for improved API token handling and styling * feat: refactor Memeooorr agent form and validation logic to enhance API token handling and streamline component imports * feat: update Memeooorr agent form and types to include XCredentialsKeys and enhance service description handling * feat: remove Twitter login validation and related dependencies from the application * feat: remove YourAgentCannotSignIn component and related imports from AlertSections * feat: add X username field to Memeooorr agent form and update related components * feat: update Memeooorr agent form and related components to include X username handling * feat: Update agent setup and show alert (#908) * feat: add UpdateAgentConfiguration component to alert sections * feat: remove healthcheck alert state and related logic from SharedProvider * feat: implement isMemeooorrFieldUpdateCompleted check for agent deployment and alert visibility * feat: add MemeooorrUpdateSetup component and update routing in UpdateAgentPage * feat: update loading text style to fit content and add fit-content class * feat: add clarification comments for Memeooorr agent configuration requirements * chore: bump middleware (#909) Signed-off-by: OjusWiZard * feat: update service template hash and version for Memeooorr agent * fix: add `tweepy` dependency Signed-off-by: OjusWiZard * fix: show alert on agent settings (#911) * feat: add showTokensRequiredMessage prop to XAccountApiTokens and display alert * feat: update MemeooorrAgentForm to use agentFormType prop for variant handling * fix: update hash and service version for AGENTS_FUN_COMMON_TEMPLATE --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * fix: update version to 0.2.0-rc173 in package.json and pyproject.toml * fix: update service template hashes and version for Trader and Optimus agents (#926) * fix: update version to 0.2.0-rc174 in package.json and pyproject.toml * feat: update middleware (#929) * fix: update coverage and typing-inspection versions in poetry.lock and pyproject.toml * fix: update pluggy, pycryptodome, and setuptools versions in poetry.lock * chore: update middleware: bridging, but NOT split-binaries --------- Co-authored-by: jmoreira-valory * fix: update version to 0.2.0-rc175 in package.json and pyproject.toml --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * chore: fix pyproject (#939) * feat: staging to main (#933) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) * feat: modius hash update (#916) * fix: update hash for Modius service template * fix: update hash for Modius service template * fix: update hash for Modius service template * feat: staging to main (#913) (#919) * release: 0.2.0-rc170 * fix: Make Gemini API key optional in Modius setup (#898) * feat: add optional field props for Modius agent forms * feat: update Modius agent form to use optional field props * Update frontend/components/SetupPage/SetupYourAgent/shared/formUtils.ts --------- * chore: update middleware (#901) * chore: staging-ea to staging (#900) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- * release: 0.2.0-rc270 * chore: update middleware --------- * chore: remove tests * feat: pearl link update (#912) * chore: update URLs for operate section to point to pearl * chore: update URLs to point to Pearl instead of Operate * chore: bump version to 0.2.0-rc171 (#903) * fix: update hash for Trader Agent service template (#917) --------- Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory * fix: update hash for Trader Agent service template (#921) * fix: update comment for Trader Agent name uniqueness * feat: FE implementation of New Agents.fun setup integration (#907) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge to manage token inputs with state and improve button functionality * feat: implement handleBridgeFunds function and update button click handler in AddFundsThroughBridge * feat: refactor AddFundsSection to separate AddFundsBy component and improve fund type selection logic * refactor: simplify onChange handler for fund type selection in AddFundsBy and SetupEoaFunding components * feat: API integration for "Bridge in progress" screen (#853) * feat: move icon styles to a shared file * feat: integrate bridge status fetching with API using react-query * fix: update bridging steps status handling and simplify logic * feat: implement bridge execution logic and integrate online status checks * feat: integrate get quote endpoint (#856) * feat: integrate get quote endpoint * chore: review fixes * chore: review fixes * feat: Bridge in progress screen - master safe creation & transfer API integration (#855) * fix: adjust width of loading text and update CardSection padding prop * feat: add onboarding test scenarios for bridge states * fix: rename time prop to timeInSeconds in EstimatedCompletionTime component * docs: (after call with Jose) add detailed comments explaining master EOA transfer process in BridgeInProgress component * refactor: remove unused time remaining calculation and related component from BridgeInProgress * feat: implement backup signer hook and integrate into safe creation process * feat: enhance BridgeInProgress and SetupEoaFunding components with new hooks and UI improvements * refactor: remove mock implementation from createSafe function * refactor: improve variable naming and documentation in useMasterSafeCreation and createSafe functions * feat: Add wrapper component to handle data flow between bridging screens (#857) * fix: add alignment to CardSection components and correct border property in SetupRestore * feat: implement SetupBridge component to manage bridging process and integrate with BridgeInProgress and BridgeOnEvm refactor: update transfer handling and state management in bridging components fix: rename screen for onboarding to BridgeOnboarding * feat: implement SetupBridgeOnboarding component and update navigation for bridge onboarding process * feat: enhance bridging functionality and add bigintMax utility function * feat: bridge quote API integration and TODOs (#858) * feat: implement bridge onboarding flow with progress tracking and state management * feat: refactor bridging hooks to accept token symbols as parameters * feat: enhance bridging process with safe creation response link and update DepositForBridging props * feat: update DepositForBridging component to include CrossChainTransferDetails and improve token info handling * feat: add useEffect to handle quote updates and improve DepositForBridging functionality * feat: refactor DepositForBridging and BridgeOnEvm components for improved structure and readability * feat: add TokenBalances type and update BridgeRefillRequirementsResponse for improved balance handling * feat: refactor token balance handling and improve bridge refill requirements response structure * feat: remove mock implementations from Bridge service and streamline API calls * feat: add DepositAddress component for displaying and copying deposit address * Update frontend/components/SetupPage/Create/SetupBridgeOnboarding/BridgeInProgress.tsx Co-authored-by: Atatakai * feat: update DepositForBridging component to use bridgeFundingRequirements and include token address in token info * fix: standardize error constant naming in SetupBridgeOnboarding component * feat: enhance balance handling by introducing MasterSafeBalanceRecord type and updating refill requirements --------- Co-authored-by: Atatakai * feat: enhance SetupPassword and DepositForBridging components with user login and error handling (#861) * fix: formatting and loading in "Bridging in progress" screen (#862) * feat: enhance bridging process with loading and error states in useBridgingSteps hook * feat: remove unused setUserLoggedIn function from SetupCreateSafe component * feat: add decimals property to TokenTransfer type and update TransferRow to use dynamic decimals for amount formatting * feat: include decimals in TransferRow for accurate amount formatting * fix: display fail status if safe creation failed (#863) * feat: bridge json in export logs (#864) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: Retry and export logs for "Bridge in progress" (#865) * feat: add bridge directory path and enhance log saving functionality * Update electron/main.js * feat: add ExportLogsButton component and integrate it into HelpAndSupport page * feat: enhance bridging steps with retry functionality and log export option * feat: integrate ExportLogsButton into FundsAreSafeMessage component * fix: Improve /execute error handling and status updates (#867) * refactor: update bridging logic and improve error handling in BridgeInProgress component * fix: update bridging completion logic to check all steps for successful finish status * fix: enhance bridging status checks to accurately reflect completion state * fix: update bridging status logic to accurately reflect completion and wait states * fix: adjust bridging execution query to disable retries and improve status checks * fix: Update bridge status fetching and error handling (#868) * fix: Update bridge status fetching and improve address validation logic * fix: Remove unnecessary body from GET request in getBridgeStatus function * fix: Update bridge execution logic and improve error handling in useBridgingSteps hook * fix: improve bridging status handling and error management in BridgeInProgress component * fix: enhance bridging status checks to handle completion and failure scenarios * feat: implement BridgeInProgress component and related hooks for managing bridging steps and master safe creation * fix: bridge status loading (#869) * fix: update bridge status handling and improve master safe creation logic * fix: remove console logs and add delay before redirecting to main page * fix: replace delayInSeconds with setTimeout for redirecting to main page * fix: adjust precision for token display and improve number formatting logic (#870) * feat: retry bridge onboarding (#873) * fix: update Typography usage and adjust styles in SetupCreateSafe component * refactor: streamline isBridgingCompleted logic for improved clarity * refactor: simplify bridging status handling and improve readability in BridgeInProgress component * refactor: simplify isBridgingCompleted logic for improved readability * fix: update bridge retry outcome from 'NAVIGATE_TO_REFILL' to 'NEED_REFILL' for consistency * fix: bridging issues after sync (#874) * [200~fix: adjust precision for token amounts in bridge components~ * fix: clarify variable naming for fund transfer calculation in master safe creation * feat: bridging improvements (#876) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: onboarding issues after iason testing (#878) * fix: update variable names for clarity in bridging steps and retry logic * fix: add TODO comment for handling quote request failure * fix: update transaction link key in SafeCreationResponse and remove obsolete notes * fix: refactor bridge requirements handling and improve quote request failure logic * fix: simplify bridge requirements parameter handling and improve loading checks * fix: enhance bridge refill requirements handling with force update and error management * fix: refactor DepositForBridging component and introduce TokenDetails for improved token information display * fix: improve bridge refill requirements handling and simplify code structure * fix: adjust bridge status handling to ensure error state is correctly identified * feat: add new chain images for base, ethereum, gnosis, and mode chains * fix: remove unused hasAnyBridgeFailed parameter from getBridgeStats function * fix: update types for balance records and bridge request status; enhance address comparison function * fix: refactor transfer details calculation for improved readability and maintainability * fix: update token address handling for accurate balance calculations * fix: use kebabCase for chain name in image source path (#882) * feat: bridging changes to bridging feature branch (#892) * feat: update tools accuracy hash * release: 0.2.0-rc163 * release: 0.2.0-rc257 * feat: update hash for Optimus service template (#838) * feat: update modius hash * feat: update modius hash * feat: support new staking contracts * feat: update agent hash and MW version * release: 0.2.0-rc164 * feat: deprecate old contracts * fix: allow switching contracts * fix: requests count call * feat: update modius hash * chore: review fixes * fix: requests counter for trader * fix: contract call * release: 0.2.0-rc258 * release: 0.2.0-rc165 * fix: remove minimum from modius funds, change default agentsfun contract * release: 0.2.0-rc166 * feat: update modius hash * feat: update modius hash * fix number overflow issue * chore: fix types * feat: update trader hash * chore: update pyproject * chore: update middleware * feat: update accuracy hash and set mech interact timeout * fix: ensure correct type assertion for token address in getFromToken helper * fix: default agents.fun staking contract * refactor: comment out unused Modius onboarding step and update image asset * refactor: comment out 'Take action' step in Modius onboarding * fix: update description in Modius onboarding steps to include Velodrome * feat: update trader accuracy hash and agents.fun hash * chore: update middleware * fix: windows build * chore: update middleware * chore: update middleware * chore: update middleware * chore: update middleware * feat: update modius hash and fix win build * fix: build for win * fix: build for win * fix: build for win * feat: new hashes * fix: use kebabCase for chain name in image source path (#882) (#883) * chore: update middleware * feat: update modius hash * feat: roll back trader hash * release/020-rc169 * chore: update middleware * fix: safe creation initial funds calculation (#885) * feat: add totalRequirements to BalancesAndRefillRequirementsProvider context * fix: update useMasterSafeCreationAndTransfer to use totalRequirements instead of refillRequirements * fix: logic update for initial funding (#889) * feat: enhance bridge refill logic and add debug logging * feat: implement updated bridge requirements calculation and refactor related logic * fix: improve bridge requirements calculation and handle native token case * chore: address review changes * feat: use "transfer_excess_assets" instead of initial funds (#890) * chore: update middleware --------- Co-authored-by: Atatakai Co-authored-by: jmoreira-valory * chore: poetry lock * fix: bridge amount to be initial funds (#893) * refactor: clean up imports and simplify balance calculations in DepositForBridging component * refactor: simplify toToken retrieval logic in DepositForBridging component * fix: hide "Fund your agent" alert after bridging (#894) * fix: integrate electron API for initial funding status update * fix: add TODO for future backend logic migration in success handler * feat: bridge through "Add funds" behind feature flag and disabled (#895) * feat: enhance feature flag handling for bridging funds * refactor: rename feature flags for bridging funds to improve clarity * feat: add bridge funds button with tooltip for availability --------- Co-authored-by: jmoreira-valory Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * release: 0.2.0-rc270 * chore: update middleware * feat: memeooorr consolidate form (#904) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * feat: memeooorr add new fields to form (#905) * refactor: move ErrorComponent to AgentButton and remove unused file * feat: add Memeooorr agent form with validation and Fireworks API integration * feat: implement Memeooorr agent form with validation and Fireworks API integration * feat: refactor Memeooorr agent form to handle cookies and update setup flow * feat: enhance Memeooorr agent form with improved state management and validation integration * refactor: remove Twitter validation logic and associated types from Memeooorr agent form * chore: add TODO comments for product clarification in YourAgentCannotSignIn and AgentTitle components * feat: refactor Memeooorr agent form and related components to integrate new API keys and remove deprecated fields * feat: update Memeooorr agent form and setup components for improved API token handling and styling * feat: refactor Memeooorr agent form and validation logic to enhance API token handling and streamline component imports * feat: update Memeooorr agent form and types to include XCredentialsKeys and enhance service description handling * feat: remove Twitter login validation and related dependencies from the application * feat: remove YourAgentCannotSignIn component and related imports from AlertSections * feat: add X username field to Memeooorr agent form and update related components * feat: update Memeooorr agent form and related components to include X username handling * feat: Update agent setup and show alert (#908) * feat: add UpdateAgentConfiguration component to alert sections * feat: remove healthcheck alert state and related logic from SharedProvider * feat: implement isMemeooorrFieldUpdateCompleted check for agent deployment and alert visibility * feat: add MemeooorrUpdateSetup component and update routing in UpdateAgentPage * feat: update loading text style to fit content and add fit-content class * feat: add clarification comments for Memeooorr agent configuration requirements * chore: bump middleware (#909) Signed-off-by: OjusWiZard * feat: update service template hash and version for Memeooorr agent * fix: add `tweepy` dependency Signed-off-by: OjusWiZard * fix: show alert on agent settings (#911) * feat: add showTokensRequiredMessage prop to XAccountApiTokens and display alert * feat: update MemeooorrAgentForm to use agentFormType prop for variant handling * fix: update hash and service version for AGENTS_FUN_COMMON_TEMPLATE --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: jmoreira-valory Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard * fix: update version to 0.2.0-rc173 in package.json and pyproject.toml * fix: update service template hashes and version for Trader and Optimus agents (#926) * fix: update version to 0.2.0-rc174 in package.json and pyproject.toml * feat: update middleware (#929) * fix: update coverage and typing-inspection versions in poetry.lock and pyproject.toml * fix: update pluggy, pycryptodome, and setuptools versions in poetry.lock * chore: update middleware: bridging, but NOT split-binaries --------- Co-authored-by: jmoreira-valory * fix: update version to 0.2.0-rc175 in package.json and pyproject.toml * chore: fix poetry deps * feat: staging-ea to staging (#925) * release: 0.2.0-rc257 * release: 0.2.0-rc258 * feat: Automated bridging OLAS & ETH for Agents.fun onboarding (EA) (#837) * chore: update middleware * chore: update middleware * feat: feature flag and switch for onboarding (#832) * feat: add segmented control for fund transfer options in AddFundsSection * feat: add bridge-funds feature flag to configuration * feat: implement bridge funds feature with UI components and enable feature flag * feat: enhance SetupEoaFunding component with new styled cards and improved layout * feat: update chain logo paths and add new chain images * style: standardize quotation marks in AddFundsSection component * refactor: simplify AddFundsSection component and remove unused Segmented options * feat: update fund type options in SetupEoaFunding component to reflect new terminology * feat: bridging in progress components (#839) * feat: add button for bridging funds and update text description * feat: implement bridging flow with progress indicator and update setup screens * feat: enhance bridging flow with transfer details and conditional back button * feat: update bridge transfer flow to display formatted amounts and improve component structure * feat: refactor bridge transfer flow and add bridging steps component * feat: add deposit for bridging component * chore: review fixes * chore: update middleware * feat: add tooltips * chore: update middleware * chore: update middleware * feat: enhance "Bridge In Progress" component - transfer & receive table (#841) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * chore: update middleware * feat: add BridgingSteps component for in progress screen (#843) * feat: enhance BridgeInProgress component with header and API integration placeholders * feat: update bridge transfer flow to use token symbols and enhance rendering logic * feat: refactor BridgeInProgress component and improve CardFlex styling * feat: enhance BridgeInProgress component layout and update estimated time display * refactor: simplify BridgeInProgress component structure and rename EstimatedTime to EstimatedCompletionTime * feat: add BridgingSteps component to BridgeInProgress screen * feat: implement BridgingSteps component with dynamic step data and transaction links (init, need to polish) * feat: enhance BridgingSteps component with improved transaction links and loading indicators; add new styles for padding and text color * feat: add FundsAreSafeMessage component for improved error handling and user guidance; update BridgingSteps component status and layout * refactor: rename SubStep to SubStepRow and extract Desc and TxnDetails components for better readability; update BridgingSteps component structure * feat: update BridgingSteps component to handle dynamic transaction statuses and improve error handling; refactor subStep structure for clarity * feat: implement bridge status retrieval and integrate with BridgingSteps component; add necessary types and constants * feat: update bridging step statuses and types for improved clarity and consistency; refactor related components * feat: update bridge creation status to 'process' in BridgeInProgress component; enhance bridge status retrieval logic * feat: deleted API (later) * feat: enhance bridging steps and master safe transfer logic; refactor related components for improved clarity * refactor: replace Nullable with Maybe in type definitions; remove unused TEN_SECONDS_INTERVAL constant * feat: simplify transaction status descriptions in master safe creation step * Update frontend/types/Bridge.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * refactor: update bridging status and safe creation logic; replace SetupScreen with Pages enum * refactor: rename subSteps to computedSubSteps in bridging steps and related functions * docs: update comments for BridgingStepStatus to clarify step statuses --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat: Quote estimated time (#848) * feat: implement EstimatedCompletionTime component for displaying estimated time * feat: integrate time remaining calculation into EstimatedCompletionTime component * Update frontend/components/SetupPage/Create/BridgeInProgress.tsx * feat: add api callbacks (#846) * feat: add api callbacks * chore: update type * chore: fix request params * chore: review fixes * feat: add funds using bridge (#850) * feat: add fund type selection and bridge support in AddFundsSection * feat: refactor AddFundsSection to include fund type selection and bridge functionality * feat: integrate WhatAreStakingContractsSection into ManageStakingPage * feat: add AddFundsThroughBridge page and integrate with AddFundsSection * feat: implement NumberInput component and integrate into AddFundsThroughBridge * feat: refactor AddFundsThroughBridge to use Form for token amount input and improve component structure * feat: refactor AddFundsThroughBridge … --------- Signed-off-by: OjusWiZard Co-authored-by: Atatakai Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: jmoreira-valory <96571377+jmoreira-valory@users.noreply.github.com> Co-authored-by: jmoreira-valory Co-authored-by: Ojuswi Rastogi <55619686+OjusWiZard@users.noreply.github.com> Co-authored-by: OjusWiZard --- frontend/client/types.ts | 2 +- frontend/constants/serviceTemplates.ts | 24 +++++++++++++++--------- frontend/utils/service.ts | 10 +++++++++- package.json | 2 +- pyproject.toml | 2 +- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index f37c08092..95e68dc7e 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -77,7 +77,7 @@ export type MiddlewareServiceResponse = { export type ServiceTemplate = { agentType: AgentType; - name: string; + name: string; // Should be unique across all services hash: string; description: string; image: string; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 31859ce2f..af181076e 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -7,11 +7,17 @@ import { STAKING_PROGRAM_IDS } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { parseEther, parseUnits } from '@/utils/numberFormatters'; +/** + * Prefix for KPI description in service templates. + * This is used track services that are part of the Pearl service suite. + */ +export const KPI_DESC_PREFIX = '[Pearl service]'; + export const PREDICT_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.PredictTrader, // TODO: remove if causes errors on middleware name: 'Trader Agent', // should be unique across all services and not be updated hash: 'bafybeihe7r2a2vnbbqrzczlzjhhmzypxbre3gobupc65w4ea266hmk5efu', - description: 'Trader agent for omen prediction markets', + description: `${KPI_DESC_PREFIX} Trader agent for omen prediction markets`, image: 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', service_version: 'v0.25.5', @@ -83,7 +89,7 @@ export const PREDICT_SERVICE_TEMPLATE: ServiceTemplate = { name: 'Tools accuracy hash', description: '', // Use the latest value from https://github.com/valory-xyz/quickstart/blob/main/configs/config_predict_trader.json#L74 - value: 'QmTzMoaEtSRdAnVxpziXVNwqYcE6HVZpGs6TM8vhWw1HPt', + value: 'QmSJ9CRvEjwsQCckMG9NXtxkQrtmmgnjpxfnTLoA1jQsUm', provision_type: EnvProvisionType.FIXED, }, MECH_INTERACT_ROUND_TIMEOUT_SECONDS: { @@ -99,10 +105,10 @@ const AGENTS_FUN_COMMON_TEMPLATE: Pick< ServiceTemplate, 'env_variables' | 'hash' | 'image' | 'description' | 'service_version' > = { - hash: 'bafybeiajnpysvflxlbsynl4ybsdhgbbrx5hdjvzzdsxnbb6ejia4mrdmdi', + hash: 'bafybeiaymgtbsxf6zyoedpgocdjqd5qfnyr3ugybwo7u3iqyiseti4bzke', image: 'https://gateway.autonolas.tech/ipfs/QmQYDGMg8m91QQkTWSSmANs5tZwKrmvUCawXZfXVVWQPcu', - description: 'Memeooorr @twitter_handle', // should be overwritten with twitter username + description: `${KPI_DESC_PREFIX} Memeooorr @twitter_handle`, // NOTE: @twitter_handle to be replaced with twitter username service_version: 'v0.5.0-alpha3', env_variables: { BASE_LEDGER_RPC: { @@ -210,7 +216,7 @@ const AGENTS_FUN_COMMON_TEMPLATE: Pick< */ export const AGENTS_FUN_BASE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Memeooorr, - name: 'Memeooorr', // Should be unique across all services and not be updated + name: 'Memeooorr', home_chain: MiddlewareChain.BASE, configurations: { [MiddlewareChain.BASE]: { @@ -239,7 +245,7 @@ export const AGENTS_FUN_BASE_TEMPLATE: ServiceTemplate = { */ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = { agentType: AgentType.AgentsFunCelo, - name: 'Memeooorr - Celo', // Should be unique across all services and not be updated + name: 'Memeooorr - Celo', home_chain: MiddlewareChain.CELO, configurations: { [MiddlewareChain.CELO]: { @@ -264,9 +270,9 @@ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = { export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Modius, - name: 'Optimus', // Should be unique across all services and not be updated - hash: 'bafybeicxflz5lzklgc522zytvwi4rgycghdqdmzgkxojnjatommr7qvqfm', - description: 'Optimus', + name: 'Optimus', + hash: 'bafybeidjtlrave3ck3usj3cr3wd6vjjipa7dhcoxv6manoqo6mayiyjuu4', + description: `${KPI_DESC_PREFIX} Optimus`, image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', service_version: 'v0.3.15', diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index 5198f900f..94e9f6fa0 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -1,7 +1,10 @@ import { isEmpty, isNil } from 'lodash'; import { EnvProvisionType, ServiceTemplate } from '@/client'; -import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; +import { + KPI_DESC_PREFIX, + SERVICE_TEMPLATES, +} from '@/constants/serviceTemplates'; import { AgentType } from '@/enums/Agent'; import { StakingProgramId } from '@/enums/StakingProgram'; import { ServicesService } from '@/service/Services'; @@ -35,6 +38,11 @@ export const updateServiceIfNeeded = async ( partialServiceTemplate.name = serviceTemplate.name; } + // If the description doesn't include "[Pearl service]" then update it + if (!service.description.includes(KPI_DESC_PREFIX)) { + partialServiceTemplate.description = `${KPI_DESC_PREFIX} ${service.description}`; + } + // Check if there's a need to update or add env variables const envVariablesToUpdate: ServiceTemplate['env_variables'] = {}; Object.entries(serviceTemplate.env_variables).forEach( diff --git a/package.json b/package.json index b6cbeec07..6b550c6cf 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "start:frontend": "cd frontend && yarn start", "test:frontend": "cd frontend && yarn test" }, - "version": "0.2.0-rc173", + "version": "0.2.0-rc176", "engine": { "node": ">=20", "yarn": ">=1.22.0", diff --git a/pyproject.toml b/pyproject.toml index a92bad4d6..afe9fdcc1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-app" -version = "0.2.0-rc173" +version = "0.2.0-rc176" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From 3c48217422e14a04ea8caa8619a2f9c3d4bf5db2 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 30 May 2025 16:13:31 +0200 Subject: [PATCH 22/44] fix: poetry --- poetry.lock | 6 +++--- pyproject.toml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index c0b981bf8..bfd51dce0 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2351,8 +2351,8 @@ web3 = "==6.1.0" [package.source] type = "git" url = "https://github.com/valory-xyz/olas-operate-middleware.git" -reference = "b89441b26112ffd6b50336d9e4a987778d5b55c2" -resolved_reference = "b89441b26112ffd6b50336d9e4a987778d5b55c2" +reference = "920957b1871a533a3a63f1162d9c6d10625226a8" +resolved_reference = "920957b1871a533a3a63f1162d9c6d10625226a8" [[package]] name = "open-aea" @@ -4058,4 +4058,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.12" -content-hash = "ec523d803cd8d17245d1f07b3e55ed04154f951a80d7c09ef818930faa450a06" +content-hash = "ee0d3ab758d5e2dfc4e0e984b7064f301bb3dd800b9a82a39358d4375a1e3c8e" diff --git a/pyproject.toml b/pyproject.toml index afe9fdcc1..59bdda1cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-app" -version = "0.2.0-rc176" +version = "0.2.0-rc175" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" @@ -9,7 +9,7 @@ include = [] [tool.poetry.dependencies] python = ">=3.9,<3.12" -olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "b89441b26112ffd6b50336d9e4a987778d5b55c2"} +olas-operate-middleware = { git = "https://github.com/valory-xyz/olas-operate-middleware.git", rev = "920957b1871a533a3a63f1162d9c6d10625226a8"} [build-system] requires = ["poetry-core"] From 1220fe76e9dbd45f7e9a282dcb1173c3961881b3 Mon Sep 17 00:00:00 2001 From: Mohan Date: Mon, 2 Jun 2025 14:18:33 +0530 Subject: [PATCH 23/44] feat: optimus bridging (#943) * feat: add optimism chain image and update store schema for Optimus * feat: use optional props for Gemini API key fields in Modius and Optimus forms * feat: enhance chain name display with asEvmDisplayName utility in BridgeTransferFlow and BridgingSteps components * refactor: replace asEvmDisplayName with asEvmChainDetails for improved chain name handling --- electron/public/chains/optimism-chain.png | Bin 0 -> 5094 bytes electron/store.js | 1 + .../ModiusAgentForm/ModiusAgentForm.tsx | 3 ++- .../OptimusAgentForm/OptimusAgentForm.tsx | 3 ++- .../UpdateAgentPage/ModiusUpdateForm.tsx | 3 ++- .../UpdateAgentPage/OptimusUpdateForm.tsx | 3 ++- .../components/bridge/BridgeTransferFlow.tsx | 6 ++++-- frontend/components/bridge/BridgingSteps.tsx | 3 ++- .../components/bridge/DepositForBridging.tsx | 4 ++-- frontend/hooks/useFeatureFlag.ts | 2 +- frontend/public/chains/optimism-chain.png | Bin 0 -> 5094 bytes frontend/types/Bridge.ts | 4 ++-- frontend/utils/middlewareHelpers.ts | 2 ++ 13 files changed, 22 insertions(+), 12 deletions(-) create mode 100644 electron/public/chains/optimism-chain.png create mode 100644 frontend/public/chains/optimism-chain.png diff --git a/electron/public/chains/optimism-chain.png b/electron/public/chains/optimism-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..f7ef4d67227630f97af513c782a05c96d85d960f GIT binary patch literal 5094 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 literal 0 HcmV?d00001 diff --git a/electron/store.js b/electron/store.js index 330eed6da..e80ed8395 100644 --- a/electron/store.js +++ b/electron/store.js @@ -26,6 +26,7 @@ const schema = { }, }, agentsFunCelo: { type: 'object', default: defaultInitialAgentSettings }, + optimus: { type: 'object', default: defaultInitialAgentSettings }, }; /** diff --git a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx b/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx index 9715ddf23..68aea30c7 100644 --- a/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx +++ b/frontend/components/SetupPage/SetupYourAgent/ModiusAgentForm/ModiusAgentForm.tsx @@ -10,6 +10,7 @@ import { useStakingProgram } from '@/hooks/useStakingProgram'; import { onDummyServiceCreation } from '@/utils/service'; import { + agentFieldOptionalProps, agentFieldProps, requiredRules, validateApiKey, @@ -186,7 +187,7 @@ export const ModiusAgentForm = ({ serviceTemplate }: ModiusAgentFormProps) => { } - {...agentFieldProps} + {...agentFieldOptionalProps} > diff --git a/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx index c92922057..2eff49099 100644 --- a/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx +++ b/frontend/components/SetupPage/SetupYourAgent/OptimusAgentForm/OptimusAgentForm.tsx @@ -10,6 +10,7 @@ import { useStakingProgram } from '@/hooks/useStakingProgram'; import { onDummyServiceCreation } from '@/utils/service'; import { + agentFieldOptionalProps, agentFieldProps, requiredRules, validateApiKey, @@ -188,7 +189,7 @@ export const OptimusAgentForm = ({ } - {...agentFieldProps} + {...agentFieldOptionalProps} > diff --git a/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx b/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx index 98098739e..f25747ee5 100644 --- a/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx +++ b/frontend/components/UpdateAgentPage/ModiusUpdateForm.tsx @@ -8,6 +8,7 @@ import { useServices } from '@/hooks/useServices'; import { Nullable } from '@/types/Util'; import { + agentFieldOptionalProps, agentFieldProps, requiredRules, validateApiKey, @@ -127,7 +128,7 @@ const ModiusUpdateForm = ({ initialFormValues }: ModiusUpdateFormProps) => { } name={['env_variables', 'GENAI_API_KEY']} - {...agentFieldProps} + {...agentFieldOptionalProps} rules={[{ validator: validateApiKey }]} > diff --git a/frontend/components/UpdateAgentPage/OptimusUpdateForm.tsx b/frontend/components/UpdateAgentPage/OptimusUpdateForm.tsx index ef2eefe49..23a57e841 100644 --- a/frontend/components/UpdateAgentPage/OptimusUpdateForm.tsx +++ b/frontend/components/UpdateAgentPage/OptimusUpdateForm.tsx @@ -8,6 +8,7 @@ import { useServices } from '@/hooks/useServices'; import { Nullable } from '@/types/Util'; import { + agentFieldOptionalProps, agentFieldProps, requiredRules, validateApiKey, @@ -127,7 +128,7 @@ const OptimusUpdateForm = ({ initialFormValues }: OptimusUpdateFormProps) => { } name={['env_variables', 'GENAI_API_KEY']} - {...agentFieldProps} + {...agentFieldOptionalProps} rules={[{ validator: validateApiKey }]} > diff --git a/frontend/components/bridge/BridgeTransferFlow.tsx b/frontend/components/bridge/BridgeTransferFlow.tsx index c2d88523c..44e6d170b 100644 --- a/frontend/components/bridge/BridgeTransferFlow.tsx +++ b/frontend/components/bridge/BridgeTransferFlow.tsx @@ -4,13 +4,15 @@ import { kebabCase } from 'lodash'; import Image from 'next/image'; import React from 'react'; +import { MiddlewareChain } from '@/client'; import { COLOR } from '@/constants/colors'; import { CrossChainTransferDetails, TokenTransfer } from '@/types/Bridge'; +import { asEvmChainDetails } from '@/utils/middlewareHelpers'; import { formatUnitsToNumber } from '@/utils/numberFormatters'; const { Text } = Typography; -const TransferChain = ({ chainName }: { chainName: string }) => ( +const TransferChain = ({ chainName }: { chainName: MiddlewareChain }) => ( ( height={20} alt="chain logo" /> - {chainName} + {asEvmChainDetails(chainName).displayName} ); diff --git a/frontend/components/bridge/BridgingSteps.tsx b/frontend/components/bridge/BridgingSteps.tsx index 5e7bbcafb..04a83ea5e 100644 --- a/frontend/components/bridge/BridgingSteps.tsx +++ b/frontend/components/bridge/BridgingSteps.tsx @@ -8,6 +8,7 @@ import { SUPPORT_URL } from '@/constants/urls'; import { TokenSymbol } from '@/enums/Token'; import { BridgingStepStatus as Status } from '@/types/Bridge'; import { Maybe, Nullable } from '@/types/Util'; +import { asEvmChainDetails } from '@/utils/middlewareHelpers'; import { ExportLogsButton } from '../ExportLogsButton'; @@ -183,7 +184,7 @@ export const BridgingSteps = ({ }: BridgingStepsProps) => { const bridgeStep: Step = useMemo(() => { return { - title: `Bridge funds to ${chainName}`, + title: `Bridge funds to ${asEvmChainDetails(chainName).displayName}`, ...generateBridgeStep(bridge.status, bridge.subSteps), }; }, [chainName, bridge]); diff --git a/frontend/components/bridge/DepositForBridging.tsx b/frontend/components/bridge/DepositForBridging.tsx index 29862dd9b..3abe413e0 100644 --- a/frontend/components/bridge/DepositForBridging.tsx +++ b/frontend/components/bridge/DepositForBridging.tsx @@ -239,8 +239,8 @@ export const DepositForBridging = ({ if (!areAllFundsReceived) return; updateQuoteId(bridgeFundingRequirements.id); updateCrossChainTransferDetails({ - fromChain: upperFirst(MiddlewareChain.ETHEREUM), - toChain: upperFirst(toMiddlewareChain), + fromChain: MiddlewareChain.ETHEREUM, + toChain: toMiddlewareChain, transfers: tokens.map((token) => { const toAmount = (() => { // TODO: reuse getFromToken function from utils.ts diff --git a/frontend/hooks/useFeatureFlag.ts b/frontend/hooks/useFeatureFlag.ts index 20ee99929..af3405771 100644 --- a/frontend/hooks/useFeatureFlag.ts +++ b/frontend/hooks/useFeatureFlag.ts @@ -93,7 +93,7 @@ const FEATURES_CONFIG = FeaturesConfigSchema.parse({ 'agent-activity': true, 'backup-via-safe': true, 'agent-settings': true, - 'bridge-onboarding': false, + 'bridge-onboarding': true, 'bridge-add-funds': false, }, }); diff --git a/frontend/public/chains/optimism-chain.png b/frontend/public/chains/optimism-chain.png new file mode 100644 index 0000000000000000000000000000000000000000..f7ef4d67227630f97af513c782a05c96d85d960f GIT binary patch literal 5094 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 literal 0 HcmV?d00001 diff --git a/frontend/types/Bridge.ts b/frontend/types/Bridge.ts index de57c7d4f..d11c6b324 100644 --- a/frontend/types/Bridge.ts +++ b/frontend/types/Bridge.ts @@ -82,7 +82,7 @@ export type TokenTransfer = { }; export type CrossChainTransferDetails = { - fromChain: string; - toChain: string; + fromChain: MiddlewareChain; + toChain: MiddlewareChain; transfers: TokenTransfer[]; }; diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts index 3c96e32e9..178da8c88 100644 --- a/frontend/utils/middlewareHelpers.ts +++ b/frontend/utils/middlewareHelpers.ts @@ -32,6 +32,8 @@ export const asEvmChainDetails = ( displayName: string; } => { switch (chain) { + case MiddlewareChain.ETHEREUM: + return { name: 'ethereum', displayName: 'Ethereum' }; case MiddlewareChain.GNOSIS: return { name: 'gnosis', displayName: 'Gnosis' }; case MiddlewareChain.BASE: From b51f1119703e03d5351c6cdeeb91a15d0b4e3642 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Mon, 2 Jun 2025 15:16:36 +0530 Subject: [PATCH 24/44] feat: update hash for Modius service template --- frontend/constants/serviceTemplates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index af181076e..809a0bfcf 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -271,7 +271,7 @@ export const AGENTS_FUN_CELO_TEMPLATE: ServiceTemplate = { export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Modius, name: 'Optimus', - hash: 'bafybeidjtlrave3ck3usj3cr3wd6vjjipa7dhcoxv6manoqo6mayiyjuu4', + hash: 'bafybeicumxyzmrvqzunupg6unx7geabzuw2tskhoa6wgk4cb6gv2rp5dqq', description: `${KPI_DESC_PREFIX} Optimus`, image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', From 2d06d8e4aa7f6494273edffabdad8e753c4f9701 Mon Sep 17 00:00:00 2001 From: mohandast52 Date: Mon, 2 Jun 2025 15:24:05 +0530 Subject: [PATCH 25/44] feat: prepend KPI description prefix to Optimus service deployment description --- frontend/constants/serviceTemplates.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 809a0bfcf..f963accb6 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -422,8 +422,8 @@ export const MODIUS_SERVICE_TEMPLATE: ServiceTemplate = { export const OPTIMUS_SERVICE_TEMPLATE: ServiceTemplate = { agentType: AgentType.Optimus, name: 'Optimus - Optimism', - hash: 'bafybeicumxyzmrvqzunupg6unx7geabzuw2tskhoa6wgk4cb6gv2rp5dqq', - description: 'Optimus service deployment on Optimism network', + hash: 'bafybeif2jmhpxfx7snlpfsyifgron53fwjp5crtdxsjn4qslbsz6cdymsm', + description: `${KPI_DESC_PREFIX} Optimus service deployment on Optimism network`, image: 'https://gateway.autonolas.tech/ipfs/bafybeiaakdeconw7j5z76fgghfdjmsr6tzejotxcwnvmp3nroaw3glgyve', service_version: 'v0.3.15', From 9fce7a5b48d2e9799f799055460027472b69e9a5 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Mon, 2 Jun 2025 18:25:14 +0400 Subject: [PATCH 26/44] feat: update buttons on main page --- frontend/components/Layout/TopBar.tsx | 26 ++- .../MainPage/header/AgentProfileButton.tsx | 214 +++++++++++++++++ .../MainPage/header/AgentSettingsButton.tsx | 51 ++++ frontend/components/MainPage/header/index.tsx | 25 +- .../MainPage/sections/SwitchAgentSection.tsx | 54 ++--- .../components/YourWalletPage/AgentTitle.tsx | 217 +----------------- .../components/custom-icons/AgentProfile.tsx | 17 ++ 7 files changed, 326 insertions(+), 278 deletions(-) create mode 100644 frontend/components/MainPage/header/AgentProfileButton.tsx create mode 100644 frontend/components/MainPage/header/AgentSettingsButton.tsx create mode 100644 frontend/components/custom-icons/AgentProfile.tsx diff --git a/frontend/components/Layout/TopBar.tsx b/frontend/components/Layout/TopBar.tsx index d00c2379f..4eb45e6f2 100644 --- a/frontend/components/Layout/TopBar.tsx +++ b/frontend/components/Layout/TopBar.tsx @@ -1,8 +1,11 @@ -import { Typography } from 'antd'; +import { QuestionCircleOutlined, SettingOutlined } from '@ant-design/icons'; +import { Button, Flex, Typography } from 'antd'; import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; +import { Pages } from '@/enums/Pages'; import { useElectronApi } from '@/hooks/useElectronApi'; +import { usePageState } from '@/hooks/usePageState'; import { useStore } from '@/hooks/useStore'; const { Text } = Typography; @@ -11,7 +14,6 @@ const TrafficLightIcon = styled.div` width: 12px; height: 12px; border-radius: 50%; - margin-left: 8px; -webkit-app-region: no-drag; `; @@ -29,6 +31,7 @@ const DisabledLight = styled(TrafficLightIcon)` const TrafficLights = styled.div` display: flex; + gap: 8px; align-items: center; margin-right: 24px; -webkit-app-region: no-drag; @@ -40,9 +43,10 @@ const TopBarContainer = styled.div` left: 0; right: 0; z-index: 1; + height: 45px; display: flex; align-items: center; - padding: 10px 8px; + padding: 0px 24px; border-radius: 8px 8px 0 0px; border-bottom: 1px solid ${COLOR.BORDER_GRAY}; background: ${COLOR.WHITE}; @@ -52,6 +56,7 @@ const TopBarContainer = styled.div` export const TopBar = () => { const electronApi = useElectronApi(); const store = useStore(); + const { goto } = usePageState(); const envName = store?.storeState?.environmentName; return ( @@ -63,6 +68,21 @@ export const TopBar = () => { {`Pearl (beta) ${envName ? `(${envName})` : ''}`.trim()} + + + + + + + + + ); +}; + +export const AgentProfileButton = () => { + const { middlewareChain, serviceSafe } = useYourWallet(); + const { selectedAgentType, selectedService } = useServices(); + const { service, deploymentStatus } = useService( + selectedService?.service_config_id, + ); + const { goto, show } = useAgentUi(); + + const handleAgentUiBrowserLinkClick = useCallback(async () => { + if (!goto || !show) { + message.error('Agent UI browser IPC methods are not available'); + return; + } + + if (deploymentStatus !== MiddlewareDeploymentStatus.DEPLOYED) { + message.error( + 'Please run the agent first, before attempting to view the agent UI', + ); + return; + } + + try { + await goto('http://127.0.0.1:8716'); + show(); + } catch (error) { + message.error('Failed to open agent UI browser'); + console.error(error); + } + }, [deploymentStatus, goto, show]); + + const agentProfileLink: JSX.Element | null = useMemo(() => { + if (!serviceSafe?.address) return null; + + // gnosis - trader + if ( + middlewareChain === MiddlewareChain.GNOSIS && + selectedAgentType === AgentType.PredictTrader + ) { + return ( + + ); + } + + // base - memeooorr + const xUsername = getXUsername(service); + if ( + middlewareChain === MiddlewareChain.BASE && + selectedAgentType === AgentType.Memeooorr + ) { + return ( + + ); + } + + // mode - modius + if ( + middlewareChain === MiddlewareChain.MODE && + selectedAgentType === AgentType.Modius + ) { + return ; + } + + // optimism - optimus + if ( + middlewareChain === MiddlewareChain.OPTIMISM && + selectedAgentType === AgentType.Optimus + ) { + return ; + } + + return null; + }, [ + serviceSafe, + handleAgentUiBrowserLinkClick, + middlewareChain, + selectedAgentType, + service, + ]); + + return agentProfileLink; +}; diff --git a/frontend/components/MainPage/header/AgentSettingsButton.tsx b/frontend/components/MainPage/header/AgentSettingsButton.tsx new file mode 100644 index 000000000..c691b88ce --- /dev/null +++ b/frontend/components/MainPage/header/AgentSettingsButton.tsx @@ -0,0 +1,51 @@ +import { ControlOutlined } from '@ant-design/icons'; +import { Button, Tooltip, Typography } from 'antd'; + +import { Pages } from '@/enums/Pages'; +import { useFeatureFlag } from '@/hooks/useFeatureFlag'; +import { usePageState } from '@/hooks/usePageState'; + +const { Text } = Typography; + +export const AgentSettingsButton = () => { + const { goto } = usePageState(); + + const isAgentSettingsEnabled = useFeatureFlag('agent-settings'); + + const handleClick = (e: React.MouseEvent) => { + e.stopPropagation(); + goto(Pages.UpdateAgentTemplate); + }; + + if (isAgentSettingsEnabled) { + return ( + ) : ( @@ -97,7 +67,9 @@ export const SwitchAgentSection = () => { content="To switch, stop the agent you're running" showArrow={false} > - + )} diff --git a/frontend/components/YourWalletPage/AgentTitle.tsx b/frontend/components/YourWalletPage/AgentTitle.tsx index e240490fd..1e11ba0a3 100644 --- a/frontend/components/YourWalletPage/AgentTitle.tsx +++ b/frontend/components/YourWalletPage/AgentTitle.tsx @@ -1,224 +1,13 @@ -import { - Button, - Checkbox, - Flex, - message, - Modal, - Tooltip, - Typography, -} from 'antd'; +import { Flex, Tooltip, Typography } from 'antd'; import Image from 'next/image'; -import { useCallback, useMemo, useState } from 'react'; -import { MiddlewareChain, MiddlewareDeploymentStatus } from '@/client'; -import { NA, UNICODE_SYMBOLS } from '@/constants/symbols'; -import { GEMINI_API_URL } from '@/constants/urls'; -import { MODAL_WIDTH } from '@/constants/width'; -import { useAgentUi } from '@/context/AgentUiProvider'; -import { AgentType } from '@/enums/Agent'; -import { Pages } from '@/enums/Pages'; -import { useElectronApi } from '@/hooks/useElectronApi'; -import { usePageState } from '@/hooks/usePageState'; -import { useService } from '@/hooks/useService'; -import { useServices } from '@/hooks/useServices'; -import { useStore } from '@/hooks/useStore'; +import { NA } from '@/constants/symbols'; import { Address } from '@/types/Address'; import { generateName } from '@/utils/agentName'; -import { getXUsername } from '@/utils/x'; - -import { useYourWallet } from './useYourWallet'; const { Text, Paragraph } = Typography; -const AgentProfile = () => <>Agent profile {UNICODE_SYMBOLS.EXTERNAL_LINK}; - -const ExternalAgentProfileLink = ({ href }: { href: string }) => { - return ( - - - - ); -}; - -const PortfolioAndChatUi = ({ onClick }: { onClick: () => void }) => { - const electronApi = useElectronApi(); - const { storeState } = useStore(); - const { selectedService, selectedAgentType } = useServices(); - const { goto } = usePageState(); - - const [isModalOpen, setIsModalOpen] = useState(false); - const [dontShowAgain, setDontShowAgain] = useState(false); - - const geminiApiKey = selectedService?.env_variables?.GENAI_API_KEY?.value; - - const canAccessProfile = useMemo(() => { - if (!storeState) return false; - if (selectedAgentType === AgentType.Modius) { - return storeState.modius?.isProfileWarningDisplayed ?? false; - } - if (selectedAgentType === AgentType.Optimus) { - return storeState.optimus?.isProfileWarningDisplayed ?? false; - } - return false; - }, [storeState, selectedAgentType]); - - const handleAgentProfileClick = useCallback(() => { - if (!!geminiApiKey || canAccessProfile) { - onClick(); - return; - } - - setIsModalOpen(true); - }, [geminiApiKey, canAccessProfile, onClick]); - - const handleDoNotShowAgain = useCallback( - (value: boolean) => { - const key = `${selectedAgentType}.isProfileWarningDisplayed`; - electronApi.store?.set?.(key, value); - setIsModalOpen(false); - }, - [electronApi.store, selectedAgentType], - ); - - const handleProvideKey = useCallback(() => { - handleDoNotShowAgain(dontShowAgain); - goto(Pages.UpdateAgentTemplate); - }, [dontShowAgain, handleDoNotShowAgain, goto]); - - const handleProceed = useCallback(() => { - handleDoNotShowAgain(dontShowAgain); - onClick(); - }, [dontShowAgain, handleDoNotShowAgain, onClick]); - - const agentName = useMemo(() => { - if (selectedAgentType === AgentType.Modius) return 'Modius'; - if (selectedAgentType === AgentType.Optimus) return 'Optimus'; - return NA; - }, [selectedAgentType]); - - return ( - <> - - - - setIsModalOpen(false)} - width={MODAL_WIDTH} - footer={null} - > - -
      - To unlock the full functionality of {agentName} profile, a Gemini - API key is required. You can get a free Gemini API key through the{' '} - - Google AI Studio - - . -
      - - - setDontShowAgain(e.target.checked)}> - {"Don't show again"} - - - - - - - -
      -
      - - ); -}; - export const AgentTitle = ({ address }: { address: Address }) => { - const { middlewareChain } = useYourWallet(); - const { selectedAgentType, selectedService } = useServices(); - const { service, deploymentStatus } = useService( - selectedService?.service_config_id, - ); - const { goto, show } = useAgentUi(); - - const handleAgentUiBrowserLinkClick = useCallback(async () => { - if (!goto || !show) { - message.error('Agent UI browser IPC methods are not available'); - return; - } - - if (deploymentStatus !== MiddlewareDeploymentStatus.DEPLOYED) { - message.error( - 'Please run the agent first, before attempting to view the agent UI', - ); - return; - } - - try { - await goto('http://127.0.0.1:8716'); - show(); - } catch (error) { - message.error('Failed to open agent UI browser'); - console.error(error); - } - }, [deploymentStatus, goto, show]); - - const agentProfileLink: JSX.Element | null = useMemo(() => { - if (!address) return null; - - // gnosis - trader - if ( - middlewareChain === MiddlewareChain.GNOSIS && - selectedAgentType === AgentType.PredictTrader - ) { - return ( - - ); - } - - // base - memeooorr - const xUsername = getXUsername(service); - if ( - middlewareChain === MiddlewareChain.BASE && - selectedAgentType === AgentType.Memeooorr - ) { - return ( - - ); - } - - // mode - modius - if ( - middlewareChain === MiddlewareChain.MODE && - selectedAgentType === AgentType.Modius - ) { - return ; - } - - // optimism - optimus - if ( - middlewareChain === MiddlewareChain.OPTIMISM && - selectedAgentType === AgentType.Optimus - ) { - return ; - } - - return null; - }, [ - address, - handleAgentUiBrowserLinkClick, - middlewareChain, - selectedAgentType, - service, - ]); - return ( @@ -245,8 +34,6 @@ export const AgentTitle = ({ address }: { address: Address }) => { > {address ? generateName(address) : NA} - - {agentProfileLink} diff --git a/frontend/components/custom-icons/AgentProfile.tsx b/frontend/components/custom-icons/AgentProfile.tsx new file mode 100644 index 000000000..782d4bb44 --- /dev/null +++ b/frontend/components/custom-icons/AgentProfile.tsx @@ -0,0 +1,17 @@ +export const AgentProfileSvg = () => ( + + + +); From 137de073e6f48eef2a7dabbefed1ba7c54a00949 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Mon, 2 Jun 2025 19:30:57 +0400 Subject: [PATCH 27/44] chore: review fixes --- .../MainPage/header/AgentProfileButton.tsx | 10 ++++----- .../MainPage/header/AgentSettingsButton.tsx | 21 ++++++------------- 2 files changed, 11 insertions(+), 20 deletions(-) diff --git a/frontend/components/MainPage/header/AgentProfileButton.tsx b/frontend/components/MainPage/header/AgentProfileButton.tsx index 40e6634c3..65d81b789 100644 --- a/frontend/components/MainPage/header/AgentProfileButton.tsx +++ b/frontend/components/MainPage/header/AgentProfileButton.tsx @@ -1,5 +1,5 @@ import { Button, Checkbox, Flex, message, Modal } from 'antd'; -import { useCallback, useMemo, useState } from 'react'; +import { ReactNode, useCallback, useMemo, useState } from 'react'; import { MiddlewareChain, MiddlewareDeploymentStatus } from '@/client'; import { AgentProfileSvg } from '@/components/custom-icons/AgentProfile'; @@ -33,7 +33,7 @@ const ExternalAgentProfileLink = ({ href }: { href: string }) => { ); }; -const PortfolioAndChatUi = ({ onClick }: { onClick: () => void }) => { +const BabyDegenUi = ({ onClick }: { onClick: () => void }) => { const electronApi = useElectronApi(); const { selectedService, selectedAgentType } = useServices(); const { goto } = usePageState(); @@ -157,7 +157,7 @@ export const AgentProfileButton = () => { } }, [deploymentStatus, goto, show]); - const agentProfileLink: JSX.Element | null = useMemo(() => { + const agentProfileLink: ReactNode | null = useMemo(() => { if (!serviceSafe?.address) return null; // gnosis - trader @@ -190,7 +190,7 @@ export const AgentProfileButton = () => { middlewareChain === MiddlewareChain.MODE && selectedAgentType === AgentType.Modius ) { - return ; + return ; } // optimism - optimus @@ -198,7 +198,7 @@ export const AgentProfileButton = () => { middlewareChain === MiddlewareChain.OPTIMISM && selectedAgentType === AgentType.Optimus ) { - return ; + return ; } return null; diff --git a/frontend/components/MainPage/header/AgentSettingsButton.tsx b/frontend/components/MainPage/header/AgentSettingsButton.tsx index c691b88ce..55789506a 100644 --- a/frontend/components/MainPage/header/AgentSettingsButton.tsx +++ b/frontend/components/MainPage/header/AgentSettingsButton.tsx @@ -17,24 +17,15 @@ export const AgentSettingsButton = () => { goto(Pages.UpdateAgentTemplate); }; - if (isAgentSettingsEnabled) { - return ( -