From 489df50d6e451764d34f49b7a582a87a120e67a3 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Wed, 14 Aug 2024 12:00:44 +0400 Subject: [PATCH 01/46] chore: update low gas alert logic --- frontend/components/Main/MainGasBalance.tsx | 14 ++++++------- .../Main/MainHeader/AgentButton/index.tsx | 6 +++--- frontend/components/Main/MainHeader/index.tsx | 7 +++---- frontend/components/Main/MainOlasBalance.tsx | 5 ++--- frontend/constants/thresholds.ts | 1 + frontend/context/BalanceProvider.tsx | 20 +++++++++++++++++++ 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/frontend/components/Main/MainGasBalance.tsx b/frontend/components/Main/MainGasBalance.tsx index 0d1f83f26..f3b14438d 100644 --- a/frontend/components/Main/MainGasBalance.tsx +++ b/frontend/components/Main/MainGasBalance.tsx @@ -4,7 +4,6 @@ import { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; -import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useStore } from '@/hooks/useStore'; @@ -34,7 +33,7 @@ const FineDot = styled(Dot)` `; const BalanceStatus = () => { - const { isBalanceLoaded, safeBalance } = useBalance(); + const { isBalanceLoaded, isLowBalance } = useBalance(); const { storeState } = useStore(); const { showNotification } = useElectronApi(); @@ -44,35 +43,34 @@ const BalanceStatus = () => { // show notification if balance is too low useEffect(() => { if (!isBalanceLoaded) return; - if (!safeBalance) return; if (!showNotification) return; if (!storeState?.isInitialFunded) return; - if (safeBalance.ETH < LOW_BALANCE && !isLowBalanceNotificationShown) { + if (isLowBalance && !isLowBalanceNotificationShown) { showNotification('Trading balance is too low.'); setIsLowBalanceNotificationShown(true); } // If it has already been shown and the balance has increased, // should show the notification again if it goes below the threshold. - if (safeBalance.ETH >= LOW_BALANCE && isLowBalanceNotificationShown) { + if (!isLowBalance && isLowBalanceNotificationShown) { setIsLowBalanceNotificationShown(false); } }, [ isBalanceLoaded, isLowBalanceNotificationShown, - safeBalance, + isLowBalance, showNotification, storeState?.isInitialFunded, ]); const status = useMemo(() => { - if (!safeBalance || safeBalance.ETH < LOW_BALANCE) { + if (isLowBalance) { return { statusName: 'Too low', StatusComponent: EmptyDot }; } return { statusName: 'Fine', StatusComponent: FineDot }; - }, [safeBalance]); + }, [isLowBalance]); const { statusName, StatusComponent } = status; return ( diff --git a/frontend/components/Main/MainHeader/AgentButton/index.tsx b/frontend/components/Main/MainHeader/AgentButton/index.tsx index 356a45c12..42c060200 100644 --- a/frontend/components/Main/MainHeader/AgentButton/index.tsx +++ b/frontend/components/Main/MainHeader/AgentButton/index.tsx @@ -4,7 +4,6 @@ import { useCallback, useMemo } from 'react'; import { Chain, DeploymentStatus } from '@/client'; import { COLOR } from '@/constants/colors'; -import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; @@ -101,6 +100,7 @@ const AgentNotRunningButton = () => { const { setIsPaused: setIsBalancePollingPaused, safeBalance, + isLowBalance, totalOlasStakedBalance, totalEthBalance, } = useBalance(); @@ -194,7 +194,7 @@ const AgentNotRunningButton = () => { const isServiceInactive = serviceStatus === DeploymentStatus.BUILT || serviceStatus === DeploymentStatus.STOPPED; - if (isServiceInactive && safeBalance && safeBalance.ETH < LOW_BALANCE) { + if (isServiceInactive && isLowBalance) { return false; } @@ -224,7 +224,7 @@ const AgentNotRunningButton = () => { serviceStatus, storeState?.isInitialFunded, totalEthBalance, - safeBalance, + isLowBalance, ]); const buttonProps: ButtonProps = { diff --git a/frontend/components/Main/MainHeader/index.tsx b/frontend/components/Main/MainHeader/index.tsx index 78ffde06f..7dbd5560d 100644 --- a/frontend/components/Main/MainHeader/index.tsx +++ b/frontend/components/Main/MainHeader/index.tsx @@ -2,7 +2,6 @@ import { Flex } from 'antd'; import { useCallback, useEffect, useState } from 'react'; import { DeploymentStatus } from '@/client'; -import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; @@ -12,12 +11,12 @@ import { AgentHead } from './AgentHead'; import { FirstRunModal } from './FirstRunModal'; const useSetupTrayIcon = () => { - const { safeBalance } = useBalance(); + const { isLowBalance } = useBalance(); const { serviceStatus } = useServices(); const { setTrayIcon } = useElectronApi(); useEffect(() => { - if (safeBalance && safeBalance.ETH < LOW_BALANCE) { + if (isLowBalance) { setTrayIcon?.('low-gas'); } else if (serviceStatus === DeploymentStatus.DEPLOYED) { setTrayIcon?.('running'); @@ -26,7 +25,7 @@ const useSetupTrayIcon = () => { } else if (serviceStatus === DeploymentStatus.BUILT) { setTrayIcon?.('logged-out'); } - }, [safeBalance, serviceStatus, setTrayIcon]); + }, [isLowBalance, serviceStatus, setTrayIcon]); return null; }; diff --git a/frontend/components/Main/MainOlasBalance.tsx b/frontend/components/Main/MainOlasBalance.tsx index fa6d87b9b..9b11ebec7 100644 --- a/frontend/components/Main/MainOlasBalance.tsx +++ b/frontend/components/Main/MainOlasBalance.tsx @@ -122,13 +122,12 @@ const MainOlasBalanceAlert = styled.div` `; const LowTradingBalanceAlert = () => { - const { isBalanceLoaded, safeBalance } = useBalance(); + const { isBalanceLoaded, isLowBalance } = useBalance(); const { storeState } = useStore(); if (!isBalanceLoaded) return null; - if (!safeBalance) return null; if (!storeState?.isInitialFunded) return; - if (safeBalance.ETH >= LOW_BALANCE) return null; + if (!isLowBalance) return null; return ( diff --git a/frontend/constants/thresholds.ts b/frontend/constants/thresholds.ts index fb5ab3515..59d9dde02 100644 --- a/frontend/constants/thresholds.ts +++ b/frontend/constants/thresholds.ts @@ -7,4 +7,5 @@ export const MIN_ETH_BALANCE_THRESHOLDS = { }, }; +export const LOW_AGENT_BALANCE = 0.5; export const LOW_BALANCE = 2; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 12c5400ec..9e8cef062 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -16,6 +16,7 @@ import { useInterval } from 'usehooks-ts'; import { Wallet } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { LOW_AGENT_BALANCE, LOW_BALANCE } from '@/constants/thresholds'; import { TOKENS } from '@/constants/tokens'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { Token } from '@/enums/Token'; @@ -43,6 +44,7 @@ export const BalanceContext = createContext<{ safeBalance?: ValueOf; totalEthBalance?: number; totalOlasBalance?: number; + isLowBalance: boolean; wallets?: Wallet[]; walletBalances: WalletAddressNumberRecord; updateBalances: () => Promise; @@ -58,6 +60,7 @@ export const BalanceContext = createContext<{ safeBalance: undefined, totalEthBalance: undefined, totalOlasBalance: undefined, + isLowBalance: false, wallets: undefined, walletBalances: {}, updateBalances: async () => {}, @@ -195,6 +198,22 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { () => masterSafeAddress && walletBalances[masterSafeAddress], [masterSafeAddress, walletBalances], ); + const agentSafeBalance = useMemo( + () => + services?.[0]?.chain_data?.multisig && + walletBalances[services[0].chain_data.multisig], + [services, walletBalances], + ); + const isLowBalance = useMemo(() => { + if (!safeBalance || !agentSafeBalance) return false; + if ( + safeBalance.ETH < LOW_BALANCE && + // Need to check agentSafe balance as well, because it's auto-funded from safeBalance + agentSafeBalance.ETH < LOW_AGENT_BALANCE + ) + return true; + return false; + }, [safeBalance, agentSafeBalance]); useInterval( () => { @@ -215,6 +234,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { safeBalance, totalEthBalance, totalOlasBalance, + isLowBalance, wallets, walletBalances, updateBalances, From 0251aaee51a5f4c79a100da980c2031f764ec995 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Wed, 14 Aug 2024 16:42:13 +0400 Subject: [PATCH 02/46] chore: rename low gas constants --- frontend/components/Main/MainOlasBalance.tsx | 4 ++-- frontend/constants/thresholds.ts | 4 ++-- frontend/context/BalanceProvider.tsx | 9 ++++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/frontend/components/Main/MainOlasBalance.tsx b/frontend/components/Main/MainOlasBalance.tsx index 9b11ebec7..9fbbbedb0 100644 --- a/frontend/components/Main/MainOlasBalance.tsx +++ b/frontend/components/Main/MainOlasBalance.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components'; import { Alert } from '@/components/Alert'; import { COLOR } from '@/constants/colors'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { LOW_BALANCE } from '@/constants/thresholds'; +import { LOW_MASTER_SAFE_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useReward } from '@/hooks/useReward'; @@ -141,7 +141,7 @@ const LowTradingBalanceAlert = () => { Trading balance is too low - {`To run your agent, add at least $${LOW_BALANCE} XDAI to your account.`} + {`To run your agent, add at least $${LOW_MASTER_SAFE_BALANCE} XDAI to your account.`} Do it quickly to avoid your agent missing its targets and getting diff --git a/frontend/constants/thresholds.ts b/frontend/constants/thresholds.ts index 59d9dde02..9566aab8e 100644 --- a/frontend/constants/thresholds.ts +++ b/frontend/constants/thresholds.ts @@ -7,5 +7,5 @@ export const MIN_ETH_BALANCE_THRESHOLDS = { }, }; -export const LOW_AGENT_BALANCE = 0.5; -export const LOW_BALANCE = 2; +export const LOW_AGENT_SAFE_BALANCE = 0.5; +export const LOW_MASTER_SAFE_BALANCE = 2; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 9e8cef062..7ac0e16e0 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -16,7 +16,10 @@ import { useInterval } from 'usehooks-ts'; import { Wallet } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; -import { LOW_AGENT_BALANCE, LOW_BALANCE } from '@/constants/thresholds'; +import { + LOW_AGENT_SAFE_BALANCE, + LOW_MASTER_SAFE_BALANCE, +} from '@/constants/thresholds'; import { TOKENS } from '@/constants/tokens'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { Token } from '@/enums/Token'; @@ -207,9 +210,9 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { const isLowBalance = useMemo(() => { if (!safeBalance || !agentSafeBalance) return false; if ( - safeBalance.ETH < LOW_BALANCE && + safeBalance.ETH < LOW_MASTER_SAFE_BALANCE && // Need to check agentSafe balance as well, because it's auto-funded from safeBalance - agentSafeBalance.ETH < LOW_AGENT_BALANCE + agentSafeBalance.ETH < LOW_AGENT_SAFE_BALANCE ) return true; return false; From 59474d11b421922147eb9871764aef96bf7004a9 Mon Sep 17 00:00:00 2001 From: Ardian Date: Tue, 20 Aug 2024 12:33:02 +0200 Subject: [PATCH 03/46] fix: trader hash --- templates/trader.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/trader.yaml b/templates/trader.yaml index 934b2afbb..ac7f44159 100644 --- a/templates/trader.yaml +++ b/templates/trader.yaml @@ -1,6 +1,6 @@ name: "Trader Agent" description: "A single-agent service (sovereign agent) placing bets on Omen" -hash: bafybeidgjgjj5ul6xkubicbemppufgsbx5sr5rwhtrwttk2oivp5bkdnce +hash: bafybeiembjbkmym3ppclc2qnjuwzayibqp4vsv3lfq56fqelqfu6ytgv5i image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 service_version: v0.18.1 home_chain_id: 100 From 4ce058e879f5861a2b20e6f27117c0e587ef85ea Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 20 Aug 2024 16:57:15 +0200 Subject: [PATCH 04/46] chore: isort --- operate/ledger/profiles.py | 2 +- operate/services/protocol.py | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/operate/ledger/profiles.py b/operate/ledger/profiles.py index c70e9bf27..bf7fa8433 100644 --- a/operate/ledger/profiles.py +++ b/operate/ledger/profiles.py @@ -38,7 +38,7 @@ STAKING = { ChainType.GNOSIS: { "pearl_alpha": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A", - "pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d" + "pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d", } } diff --git a/operate/services/protocol.py b/operate/services/protocol.py index a7b3135fc..120355c94 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -40,7 +40,8 @@ from autonomy.chain.config import ChainConfigs, ChainType, ContractConfigs from autonomy.chain.constants import ( GNOSIS_SAFE_PROXY_FACTORY_CONTRACT, - GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_CONTRACT, MULTISEND_CONTRACT, + GNOSIS_SAFE_SAME_ADDRESS_MULTISIG_CONTRACT, + MULTISEND_CONTRACT, ) from autonomy.chain.service import ( get_agent_instances, @@ -67,9 +68,10 @@ from operate.types import ContractAddresses from operate.utils.gnosis import ( MultiSendOperation, + NULL_ADDRESS, SafeOperation, hash_payload_to_hex, - skill_input_hex_to_payload, NULL_ADDRESS, + skill_input_hex_to_payload, ) from operate.wallet.master import MasterWallet From 8a8e675f2a0b0dd54ebc3dcdb35bebdbf69ec106 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 20 Aug 2024 16:59:27 +0200 Subject: [PATCH 05/46] fix: update user params --- operate/cli.py | 9 +++++++++ operate/services/manage.py | 37 +++++++++++++++++++++++++++---------- operate/services/service.py | 8 ++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index 1eac6a3b6..f4632b70c 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -504,6 +504,14 @@ async def _create_services(request: Request) -> JSONResponse: if operate.password is None: return USER_NOT_LOGGED_IN_ERROR template = await request.json() + + print("!!!!!!!!!!!!!!!!") + from icecream import ic + + ic(template) + print(template) + import sys + manager = operate.service_manager() if len(manager.json) > 0: old_hash = manager.json[0]["hash"] @@ -528,6 +536,7 @@ async def _create_services(request: Request) -> JSONResponse: ) if template.get("deploy", False): + def _fn() -> None: manager.deploy_service_onchain_from_safe(hash=service.hash) # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done inside deploy_service_onchain diff --git a/operate/services/manage.py b/operate/services/manage.py index 730ec5c8d..6acf0b462 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -48,10 +48,7 @@ OnChainUserParams, Service, ) -from operate.types import ( - ServiceTemplate, - LedgerConfig -) +from operate.types import LedgerConfig, ServiceTemplate from operate.utils.gnosis import NULL_ADDRESS from operate.wallet.master import MasterWalletManager @@ -159,7 +156,12 @@ def load_or_create( """ path = self.path / hash if path.exists(): - return Service.load(path=path) + service = Service.load(path=path) + + if service_template is not None: + service.update_user_params_from_template(service_template=service_template) + + return service if service_template is None: raise ValueError( @@ -878,8 +880,8 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data user_params = chain_data.user_params - target_staking_program_id = user_params.staking_program_id - target_staking_contract = STAKING[ledger_config.chain][target_staking_program_id] + target_staking_program = user_params.staking_program_id + target_staking_contract = STAKING[ledger_config.chain][target_staking_program] sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) # TODO fixme @@ -925,13 +927,27 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: service_id=chain_config.chain_data.token, staking_contract=target_staking_contract, ) + self.logger.info("Checking conditions to stake.") + + staking_rewards_available = sftxb.staking_rewards_available(target_staking_contract) + staking_slots_available = sftxb.staking_slots_available(target_staking_contract) + on_chain_state = self._get_on_chain_state(chain_config=chain_config) + current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + + self.logger.info(f"use_staking={chain_config.chain_data.user_params.use_staking}") + self.logger.info(f"{staking_state=}") + self.logger.info(f"{staking_rewards_available=}") + self.logger.info(f"{staking_slots_available=}") + self.logger.info(f"{on_chain_state=}") + self.logger.info(f"{current_staking_program=}") + self.logger.info(f"{target_staking_program=}") if ( chain_config.chain_data.user_params.use_staking and staking_state == StakingState.UNSTAKED - and sftxb.staking_rewards_available(target_staking_contract) - and sftxb.staking_slots_available(target_staking_contract) - and self._get_on_chain_state(chain_config=chain_config) == OnChainState.DEPLOYED + and staking_rewards_available + and staking_slots_available + and on_chain_state == OnChainState.DEPLOYED ): self.logger.info(f"Approving staking: {chain_config.chain_data.token}") sftxb.new_tx().add( @@ -955,6 +971,7 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: service.store() current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + self.logger.info(f"{target_staking_program=}") self.logger.info(f"{current_staking_program=}") def unstake_service_on_chain(self, hash: str) -> None: diff --git a/operate/services/service.py b/operate/services/service.py index 6a476866b..ea6c563ca 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -777,6 +777,14 @@ def new( service.store() return service + def update_user_params_from_template(self, service_template: ServiceTemplate): + """Update user params from template.""" + for chain, config in service_template["configurations"].items(): + for chain, config in service_template["configurations"].items(): + self.chain_configs[chain].chain_data.user_params = OnChainUserParams.from_json(config) + + self.store() + def delete(self) -> None: """Delete a service.""" parent_directory = self.path.parent From 138c553da527df48e57c8a4b0374fc472332940a Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 20 Aug 2024 17:08:12 +0200 Subject: [PATCH 06/46] chore: whitespace --- operate/cli.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index f4632b70c..7d5285d13 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -504,14 +504,6 @@ async def _create_services(request: Request) -> JSONResponse: if operate.password is None: return USER_NOT_LOGGED_IN_ERROR template = await request.json() - - print("!!!!!!!!!!!!!!!!") - from icecream import ic - - ic(template) - print(template) - import sys - manager = operate.service_manager() if len(manager.json) > 0: old_hash = manager.json[0]["hash"] From 0f9f5dc0eb4e8a6e2a5a1f107a3a141aff25d9c5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 20 Aug 2024 17:17:53 +0100 Subject: [PATCH 07/46] bump: rc114 --- electron/install.js | 2 +- package.json | 5 ++--- pyproject.toml | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/electron/install.js b/electron/install.js index 7988e07fa..35eed6e98 100644 --- a/electron/install.js +++ b/electron/install.js @@ -14,7 +14,7 @@ const { paths } = require('./constants'); * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc112'; +const OlasMiddlewareVersion = '0.1.0rc114'; const path = require('path'); const { app } = require('electron'); diff --git a/package.json b/package.json index 857c15b20..24c7fc52b 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,6 @@ "test:frontend": "cd frontend && yarn test", "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" - }, - "version": "0.1.0-rc112" -} + "version": "0.1.0-rc114" +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index b77f08413..a9462612f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc112" +version = "0.1.0-rc114" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From 2e368cbf003675e003e53df9aea2083f8796a4ae Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 20 Aug 2024 18:15:25 +0100 Subject: [PATCH 08/46] fix: conflict resolution, electron-store 8.2 pin --- electron/store.js | 5 +- frontend/context/BalanceProvider.tsx | 23 +++ package.json | 2 +- yarn.lock | 232 ++++++++++++++++++--------- 4 files changed, 180 insertions(+), 82 deletions(-) diff --git a/electron/store.js b/electron/store.js index b8c5c9093..eafd9428a 100644 --- a/electron/store.js +++ b/electron/store.js @@ -1,3 +1,4 @@ +const Store = require('electron-store'); // set schema to validate store data const schema = { isInitialFunded: { type: 'boolean', default: false }, // TODO: reconsider this default, can be problematic if user has already funded prior to implementation @@ -16,8 +17,6 @@ const schema = { * @returns {Promise} - A promise that resolves once the store is set up. */ const setupStoreIpc = async (ipcMain, mainWindow) => { - const Store = (await import("electron-store")).default; - const store = new Store({ schema }); store.onDidAnyChange((data) => { @@ -30,7 +29,7 @@ const setupStoreIpc = async (ipcMain, mainWindow) => { ipcMain.handle('store-get', (_, key) => store.get(key)); ipcMain.handle('store-set', (_, key, value) => store.set(key, value)); ipcMain.handle('store-delete', (_, key) => store.delete(key)); - ipcMain.handle('store-clear', (_) => store.clear()); + ipcMain.handle('store-clear', (_) => store.clear()); }; module.exports = { setupStoreIpc }; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index cc417462a..dfcc70e6c 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -17,6 +17,10 @@ import { useInterval } from 'usehooks-ts'; import { Wallet } from '@/client'; import { CHAINS } from '@/constants/chains'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { + LOW_AGENT_SAFE_BALANCE, + LOW_MASTER_SAFE_BALANCE, +} from '@/constants/thresholds'; import { TOKENS } from '@/constants/tokens'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { Token } from '@/enums/Token'; @@ -44,6 +48,7 @@ export const BalanceContext = createContext<{ safeBalance?: ValueOf; totalEthBalance?: number; totalOlasBalance?: number; + isLowBalance: boolean; wallets?: Wallet[]; walletBalances: WalletAddressNumberRecord; updateBalances: () => Promise; @@ -59,6 +64,7 @@ export const BalanceContext = createContext<{ safeBalance: undefined, totalEthBalance: undefined, totalOlasBalance: undefined, + isLowBalance: false, wallets: undefined, walletBalances: {}, updateBalances: async () => {}, @@ -197,6 +203,22 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { () => masterSafeAddress && walletBalances[masterSafeAddress], [masterSafeAddress, walletBalances], ); + const agentSafeBalance = useMemo( + () => + services?.[0]?.chain_data?.multisig && + walletBalances[services[0].chain_data.multisig], + [services, walletBalances], + ); + const isLowBalance = useMemo(() => { + if (!safeBalance || !agentSafeBalance) return false; + if ( + safeBalance.ETH < LOW_MASTER_SAFE_BALANCE && + // Need to check agentSafe balance as well, because it's auto-funded from safeBalance + agentSafeBalance.ETH < LOW_AGENT_SAFE_BALANCE + ) + return true; + return false; + }, [safeBalance, agentSafeBalance]); useInterval( () => { @@ -217,6 +239,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { safeBalance, totalEthBalance, totalOlasBalance, + isLowBalance, wallets, walletBalances, updateBalances, diff --git a/package.json b/package.json index b90fa2de7..c5afe288e 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "cross-env": "^7.0.3", "dotenv": "^16.4.5", "electron-log": "^5.1.4", - "electron-store": "^9.0.0", + "electron-store": "8.2.0", "electron-updater": "^6.1.8", "ethers": "5.7.2", "ethers-multicall": "^0.2.3", diff --git a/yarn.lock b/yarn.lock index 0d084c194..146feb635 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1347,7 +1347,7 @@ ajv@^6.10.0, ajv@^6.12.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.0, ajv@^8.12.0: +ajv@^8.0.0: version "8.16.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4" integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw== @@ -1357,6 +1357,16 @@ ajv@^8.0.0, ajv@^8.12.0: require-from-string "^2.0.2" uri-js "^4.4.1" +ajv@^8.6.3: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ansi-colors@^4.1.1, ansi-colors@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" @@ -1538,13 +1548,10 @@ at-least-node@^1.0.0: resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== -atomically@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/atomically/-/atomically-2.0.3.tgz#27e47bbe39994d324918491ba7c0edb7783e56cb" - integrity sha512-kU6FmrwZ3Lx7/7y3hPS5QnbJfaohcIul5fGqf7ok+4KklIEk9tJ0C2IQPdacSbVUWv6zVHXEBWoWd6NrVMT7Cw== - dependencies: - stubborn-fs "^1.2.5" - when-exit "^2.1.1" +atomically@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/atomically/-/atomically-1.7.0.tgz#c07a0458432ea6dbc9a3506fffa424b48bccaafe" + integrity sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w== axios@^1.7.2: version "1.7.2" @@ -2024,20 +2031,21 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -conf@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/conf/-/conf-12.0.0.tgz#de7a5f091114a28bc52aa5eecc920f4710d60d7f" - integrity sha512-fIWyWUXrJ45cHCIQX+Ck1hrZDIf/9DR0P0Zewn3uNht28hbt5OfGUq8rRWsxi96pZWPyBEd0eY9ama01JTaknA== +conf@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/conf/-/conf-10.2.0.tgz#838e757be963f1a2386dfe048a98f8f69f7b55d6" + integrity sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg== dependencies: - ajv "^8.12.0" + ajv "^8.6.3" ajv-formats "^2.1.1" - atomically "^2.0.2" - debounce-fn "^5.1.2" - dot-prop "^8.0.2" - env-paths "^3.0.0" - json-schema-typed "^8.0.1" - semver "^7.5.4" - uint8array-extras "^0.3.0" + atomically "^1.7.0" + debounce-fn "^4.0.0" + dot-prop "^6.0.1" + env-paths "^2.2.1" + json-schema-typed "^7.0.3" + onetime "^5.1.2" + pkg-up "^3.1.0" + semver "^7.3.5" config-file-ts@^0.2.4: version "0.2.6" @@ -2139,12 +2147,12 @@ dayjs@^1.11.11: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e" integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== -debounce-fn@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-5.1.2.tgz#c77bc447ef36828ecdd066df7de23f475e0a6281" - integrity sha512-Sr4SdOZ4vw6eQDvPYNxHogvrxmCIld/VenC5JbNrFwMiwd7lY/Z18ZFfo+EWNG4DD9nFlAujWAo/wGuOPHmy5A== +debounce-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-4.0.0.tgz#ed76d206d8a50e60de0dd66d494d82835ffe61c7" + integrity sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ== dependencies: - mimic-fn "^4.0.0" + mimic-fn "^3.0.0" debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@^4.3.5: version "4.3.5" @@ -2256,12 +2264,12 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dot-prop@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-8.0.2.tgz#afda6866610684dd155a96538f8efcdf78a27f18" - integrity sha512-xaBe6ZT4DHPkg0k4Ytbvn5xoxgpG0jOS1dYxSOwAHPuNLjP3/OzN0gH55SrLqpx8cBfSaVt91lXYkApjb+nYdQ== +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== dependencies: - type-fest "^3.8.0" + is-obj "^2.0.0" dotenv-cli@^7.4.2: version "7.4.2" @@ -2345,13 +2353,13 @@ electron-publish@24.13.1: lazy-val "^1.0.5" mime "^2.5.2" -electron-store@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/electron-store/-/electron-store-9.0.0.tgz#7ce8209c5ae31877ee5fbced6c6cb538c746ca8c" - integrity sha512-7LZ2dR3N3bF93G2c4x+1NZ/8fpsKv6bKrMxeOQWLqdRbxvopxVqy9QXQy9axSV2O3P1kVGTj1q2wq5/W4isiOg== +electron-store@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/electron-store/-/electron-store-8.2.0.tgz#114e6e453e8bb746ab4ccb542424d8c881ad2ca1" + integrity sha512-ukLL5Bevdil6oieAOXz3CMy+OgaItMiVBg701MNlG6W5RaC0AHN7rvlqTCmeb6O7jP0Qa1KKYTE0xV0xbhF4Hw== dependencies: - conf "^12.0.0" - type-fest "^4.18.1" + conf "^10.2.0" + type-fest "^2.17.0" electron-updater@^6.1.8: version "6.2.1" @@ -2432,16 +2440,11 @@ enquirer@^2.3.0: ansi-colors "^4.1.1" strip-ansi "^6.0.1" -env-paths@^2.2.0: +env-paths@^2.2.0, env-paths@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== -env-paths@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-3.0.0.tgz#2f1e89c2f6dbd3408e1b1711dd82d62e317f58da" - integrity sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A== - err-code@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" @@ -2742,6 +2745,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-uri@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.1.tgz#cddd2eecfc83a71c1be2cc2ef2061331be8a7134" + integrity sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw== + fastq@^1.6.0: version "1.17.1" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" @@ -2789,6 +2797,13 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -3371,6 +3386,11 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -3462,10 +3482,10 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema-typed@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-8.0.1.tgz#826ee39e3b6cef536f85412ff048d3ff6f19dfa0" - integrity sha512-XQmWYj2Sm4kn4WeTYvmpKEbyPsL7nBsb647c7pMe6l02/yx2+Jfc4dT6UZkEXnIUb5LhD55r2HPsJ1milQ4rDg== +json-schema-typed@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-7.0.3.tgz#23ff481b8b4eebcd2ca123b4fa0409e66469a2d9" + integrity sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" @@ -3583,6 +3603,14 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -3728,10 +3756,15 @@ mime@^2.5.2: resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== -mimic-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-3.1.0.tgz#65755145bbf3e36954b949c16450427451d5ca74" + integrity sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ== mimic-response@^1.0.0: version "1.0.1" @@ -3949,6 +3982,13 @@ one-time@^1.0.0: dependencies: fn.name "1.x.x" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.3: version "0.9.4" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" @@ -3978,6 +4018,13 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" +p-limit@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -3992,6 +4039,13 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -4011,6 +4065,11 @@ p-try@^1.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + package-json-from-dist@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" @@ -4089,6 +4148,13 @@ picomatch@^2.0.4, picomatch@^2.2.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + plist@^3.0.4, plist@^3.0.5: version "3.1.0" resolved "https://registry.yarnpkg.com/plist/-/plist-3.1.0.tgz#797a516a93e62f5bde55e0b9cc9c967f860893c9" @@ -4800,11 +4866,16 @@ semver@^6.2.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.2, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4: +semver@^7.3.2, semver@^7.3.8, semver@^7.5.3: version "7.6.2" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== +semver@^7.3.5: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" @@ -4971,7 +5042,16 @@ string-convert@^0.2.0: resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4996,7 +5076,14 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5022,11 +5109,6 @@ strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -stubborn-fs@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/stubborn-fs/-/stubborn-fs-1.2.5.tgz#e5e244223166921ddf66ed5e062b6b3bf285bfd2" - integrity sha512-H2N9c26eXjzL/S/K+i/RHHcFanE74dptvvjM8iwzwbVcWY/zjBbgRqF3K0DY4+OD+uTTASTBvDoxPDaPN02D7g== - styled-components@^6.1.8: version "6.1.11" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.11.tgz#01948e5195bf1d39e57e0a85b41958c80e40cfb8" @@ -5245,26 +5327,16 @@ type-fest@^0.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== -type-fest@^3.8.0: - version "3.13.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.13.1.tgz#bb744c1f0678bea7543a2d1ec24e83e68e8c8706" - integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== - -type-fest@^4.18.1: - version "4.21.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.21.0.tgz#2eec399d9bda4ac686286314d07c6675fef3fdd8" - integrity sha512-ADn2w7hVPcK6w1I0uWnM//y1rLXZhzB9mr0a3OirzclKF1Wp6VzevUmzz/NRAWunOT6E8HrnpGY7xOfc6K57fA== +type-fest@^2.17.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== typescript@^5.3.3: version "5.5.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== -uint8array-extras@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/uint8array-extras/-/uint8array-extras-0.3.0.tgz#4b5714e4bf15bb36ae7fd6faeef11aae34a0af59" - integrity sha512-erJsJwQ0tKdwuqI0359U8ijkFmfiTcq25JvvzRVc1VP+2son1NJRXhxcAKJmAW3ajM8JSGAfsAXye8g4s+znxA== - undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" @@ -5330,11 +5402,6 @@ verror@^1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -when-exit@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/when-exit/-/when-exit-2.1.3.tgz#5831cdbed8ad4984645da98c4a00d4ee3a3757e7" - integrity sha512-uVieSTccFIr/SFQdFWN/fFaQYmV37OKtuaGphMAzi4DmmUlrvRBJW5WSLkHyjNQY/ePJMz3LoiX9R3yy1Su6Hw== - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -5378,7 +5445,16 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== From 5b237b9bf923fa8586fc922d2bc2622467b8e226 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 20 Aug 2024 18:18:44 +0100 Subject: [PATCH 09/46] fix: balance provider type merge conflict resolution --- frontend/context/BalanceProvider.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index dfcc70e6c..2bee8e074 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -205,8 +205,11 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { ); const agentSafeBalance = useMemo( () => - services?.[0]?.chain_data?.multisig && - walletBalances[services[0].chain_data.multisig], + services?.[0]?.chain_configs[CHAINS.GNOSIS.chainId].chain_data + ?.multisig && + walletBalances[ + services[0].chain_configs[CHAINS.GNOSIS.chainId].chain_data.multisig! + ], [services, walletBalances], ); const isLowBalance = useMemo(() => { From bb4104acb4a66d5a1c77e5138c33be995be4c7de Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 20 Aug 2024 18:30:09 +0100 Subject: [PATCH 10/46] fix: custom alert import --- frontend/components/MainPage/header/AgentButton.tsx | 2 -- frontend/components/MainPage/sections/NeedsFundsSection.tsx | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index 24ac0e71f..6fcdbdea0 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -4,7 +4,6 @@ import { useCallback, useMemo } from 'react'; import { Chain, DeploymentStatus } from '@/client'; import { COLOR } from '@/constants/colors'; -import { LOW_BALANCE } from '@/constants/thresholds'; import { StakingProgram } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; @@ -238,7 +237,6 @@ const AgentNotRunningButton = () => { return hasEnoughOlas && hasEnoughEth; }, [ serviceStatus, - safeBalance, service, storeState?.isInitialFunded, isEligibleForStaking, diff --git a/frontend/components/MainPage/sections/NeedsFundsSection.tsx b/frontend/components/MainPage/sections/NeedsFundsSection.tsx index 3b22c46f4..08ae82696 100644 --- a/frontend/components/MainPage/sections/NeedsFundsSection.tsx +++ b/frontend/components/MainPage/sections/NeedsFundsSection.tsx @@ -3,6 +3,7 @@ import { formatUnits } from 'ethers/lib/utils'; import { ReactNode, useEffect, useMemo } from 'react'; import styled from 'styled-components'; +import { CustomAlert } from '@/components/Alert'; import { CHAINS } from '@/constants/chains'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { useBalance } from '@/hooks/useBalance'; @@ -11,8 +12,6 @@ import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useStore } from '@/hooks/useStore'; import { getMinimumStakedAmountRequired } from '@/utils/service'; -import { CustomAlert } from '../../Alert'; -import { AlertTitle } from '../../Alert/AlertTitle'; import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; From 717714b5e0b3ac4e0bd3348caffa9f267a841242 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 10:08:19 +0100 Subject: [PATCH 11/46] fix: gitleaks ignore 2 keys --- .gitleaksignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitleaksignore b/.gitleaksignore index 446eb5a4b..33c8c27cf 100644 --- a/.gitleaksignore +++ b/.gitleaksignore @@ -27,4 +27,6 @@ d8149e9b5b7bd6a7ed7bc1039900702f1d4f287b:operate/services/manage.py:generic-api- 99c0f139b037da2587708212fcf6d0e20786d0ba:operate/services/manage.py:generic-api-key:406 99c0f139b037da2587708212fcf6d0e20786d0ba:operate/services/manage.py:generic-api-key:454 99c0f139b037da2587708212fcf6d0e20786d0ba:operate/services/manage.py:generic-api-key:455 -91ec07457f69e9a29f63693ac8ef887e4b5f49f0:operate/services/manage.py:generic-api-key:454 \ No newline at end of file +91ec07457f69e9a29f63693ac8ef887e4b5f49f0:operate/services/manage.py:generic-api-key:454 +410bea2bd02ff54da69387fe8f3b58793e09f7b0:operate/services/manage.py:generic-api-key:421 +410bea2bd02ff54da69387fe8f3b58793e09f7b0:operate/services/manage.py:generic-api-key:422 \ No newline at end of file From c54ab4b556bc6930db8114a36c5138d8bb6c9ff7 Mon Sep 17 00:00:00 2001 From: Ardian Date: Wed, 21 Aug 2024 12:55:43 +0200 Subject: [PATCH 12/46] fix: update trader hash --- frontend/constants/serviceTemplates.ts | 2 +- templates/trader.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index dcb2fd1aa..19948f76a 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -4,7 +4,7 @@ import { StakingProgram } from '@/enums/StakingProgram'; export const SERVICE_TEMPLATES: ServiceTemplate[] = [ { name: 'Trader Agent', - hash: 'bafybeidgjgjj5ul6xkubicbemppufgsbx5sr5rwhtrwttk2oivp5bkdnce', + hash: 'bafybeicrstlxew36hlxl7pzi73nmd44aibnhwxzkchzlec6t6yhvs7gvhy', // hash: 'bafybeibbloa4w33vj4bvdkso7pzk6tr3duvxjpecbx4mur4ix6ehnwb5uu', // temporary description: 'Trader agent for omen prediction markets', image: diff --git a/templates/trader.yaml b/templates/trader.yaml index ac7f44159..ed0b8679d 100644 --- a/templates/trader.yaml +++ b/templates/trader.yaml @@ -1,6 +1,6 @@ name: "Trader Agent" description: "A single-agent service (sovereign agent) placing bets on Omen" -hash: bafybeiembjbkmym3ppclc2qnjuwzayibqp4vsv3lfq56fqelqfu6ytgv5i +hash: bafybeicrstlxew36hlxl7pzi73nmd44aibnhwxzkchzlec6t6yhvs7gvhy image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 service_version: v0.18.1 home_chain_id: 100 From ea7eef01f442eb676cb04ff37ca05422d85741f5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 13:25:33 +0100 Subject: [PATCH 13/46] fix: missed minimum required olas string --- .../ManageStakingPage/StakingContractSection/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index b8fdf664c..d10180fd9 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -136,7 +136,7 @@ export const StakingContractSection = ({ } if (!hasEnoughOlasToMigrate) { - return 'Insufficient OLAS balance to migrate, need ${}'; + return `Insufficient OLAS balance to migrate, ${minimumOlasRequiredToMigrate} OLAS minimum required.`; } if (!isAppVersionCompatible) { From bb6eef73882e5796dc5b046d672086b11c25d93d Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:27:05 +0100 Subject: [PATCH 14/46] refactor: wordiness --- .../ManageStakingPage/StakingContractSection/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index d10180fd9..9302ef843 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -136,7 +136,7 @@ export const StakingContractSection = ({ } if (!hasEnoughOlasToMigrate) { - return `Insufficient OLAS balance to migrate, ${minimumOlasRequiredToMigrate} OLAS minimum required.`; + return `Insufficient OLAS balance to migrate, ${minimumOlasRequiredToMigrate} OLAS required.`; } if (!isAppVersionCompatible) { From fba4aacac0ffee7729363f009242090e35614e57 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Wed, 21 Aug 2024 13:27:45 +0100 Subject: [PATCH 15/46] Update index.tsx --- .../ManageStakingPage/StakingContractSection/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 9302ef843..363f7ce55 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -136,7 +136,7 @@ export const StakingContractSection = ({ } if (!hasEnoughOlasToMigrate) { - return `Insufficient OLAS balance to migrate, ${minimumOlasRequiredToMigrate} OLAS required.`; + return `Insufficient OLAS to migrate, ${minimumOlasRequiredToMigrate} OLAS required in total.`; } if (!isAppVersionCompatible) { From 1d32bb94461eb723dde8158ae5ea30358673d559 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 13:55:25 +0100 Subject: [PATCH 16/46] refactor: seperate the funding section component from the main page section --- .../MainPage/sections/AddFundsSection.tsx | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index 97bf85641..d61970e7f 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -35,23 +35,6 @@ const CustomizedCardSection = styled(CardSection)<{ border?: boolean }>` export const AddFundsSection = () => { const [isAddFundsVisible, setIsAddFundsVisible] = useState(false); - const { masterSafeAddress } = useWallet(); - - const fundingAddress: Address | undefined = masterSafeAddress; - - const truncatedFundingAddress: string | undefined = useMemo( - () => fundingAddress && truncateAddress(fundingAddress), - [fundingAddress], - ); - - const handleCopyAddress = useCallback( - () => - fundingAddress && - copyToClipboard(fundingAddress).then(() => - message.success('Copied successfully!'), - ), - [fundingAddress], - ); return ( <> @@ -75,17 +58,38 @@ export const AddFundsSection = () => { - {isAddFundsVisible && ( - <> - - - - - )} + {isAddFundsVisible && } + + ); +}; + +export const OpenAddFundsSection = () => { + const { masterSafeAddress } = useWallet(); + + const fundingAddress: Address | undefined = masterSafeAddress; + + const truncatedFundingAddress: string | undefined = useMemo( + () => fundingAddress && truncateAddress(fundingAddress), + [fundingAddress], + ); + + const handleCopyAddress = useCallback( + () => + fundingAddress && + copyToClipboard(fundingAddress).then(() => + message.success('Copied successfully!'), + ), + [fundingAddress], + ); + return ( + <> + + + ); }; From c585d5994b73bc68acb15ab4d9b93b7ee0ec6406 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 13:59:56 +0100 Subject: [PATCH 17/46] feat: add funding section to beta contract section --- .../StakingContractSection/index.tsx | 159 ++++++++++-------- 1 file changed, 91 insertions(+), 68 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index b8fdf664c..725d62ac7 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -1,7 +1,8 @@ import { Button, Flex, Popover, theme, Typography } from 'antd'; -import { useMemo } from 'react'; +import { useMemo, useState } from 'react'; import { DeploymentStatus } from '@/client'; +import { OpenAddFundsSection } from '@/components/MainPage/sections/AddFundsSection'; import { CardSection } from '@/components/styled/CardSection'; import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; @@ -59,8 +60,12 @@ export const StakingContractSection = ({ contractAddress: Address; }) => { const { goto } = usePageState(); - const { setServiceStatus, serviceStatus, setIsServicePollingPaused } = - useServices(); + const { + setServiceStatus, + serviceStatus, + setIsServicePollingPaused, + updateServiceStatus, + } = useServices(); const { serviceTemplate } = useServiceTemplates(); const { setMigrationModalOpen } = useModals(); const { activeStakingProgram, defaultStakingProgram, updateStakingProgram } = @@ -69,6 +74,7 @@ export const StakingContractSection = ({ const { token } = useToken(); const { totalOlasBalance, isBalanceLoaded } = useBalance(); const { isServiceStakedForMinimumDuration } = useStakingContractInfo(); + const [isFundingSectionOpen, setIsFundingSectionOpen] = useState(false); const stakingContractInfoForStakingProgram = stakingContractInfoRecord?.[stakingProgram]; @@ -213,40 +219,41 @@ export const StakingContractSection = ({ }, [activeStakingProgram, defaultStakingProgram, stakingProgram]); return ( - - {/* Title */} - - {`${activeStakingProgramMeta.name} contract`} - {/* TODO: pass `status` attribute */} - - {!isSelected && ( - // here instead of isSelected we should check that the contract is not the old staking contract - // but the one from staking factory (if we want to open govern) - - Contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} - - )} - - - {/* TODO: fix */} - - {/* Contract details + <> + + {/* Title */} + + {`${activeStakingProgramMeta.name} contract`} + + {!isSelected && ( + // here instead of isSelected we should check that the contract is not the old staking contract + // but the one from staking factory (if we want to open govern) + + Contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + )} + + + {/* TODO: redisplay once bugs resolved */} + + {/* Contract details {stakingContractInfo?.availableRewards && ( )} */} - {cantMigrateAlert} - {/* Switch to program button */} - {!isSelected && ( - + {cantMigrateAlert} + {/* Switch to program button */} + { + <> + + + + + } + {stakingProgram === StakingProgram.Beta && ( - + )} + + {stakingProgram === StakingProgram.Beta && isFundingSectionOpen && ( + )} - + ); }; From 15816fe07e1ed95b7474f9a634213d4d00e00632 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 17:05:58 +0100 Subject: [PATCH 18/46] fix: provider order --- frontend/pages/_app.tsx | 52 ++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 42657f818..9227cb596 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -28,19 +28,19 @@ export default function App({ Component, pageProps }: AppProps) { }, []); return ( - - - - - - - - - - - - - + + + + + + + + + + + + + {isMounted ? ( @@ -50,18 +50,18 @@ export default function App({ Component, pageProps }: AppProps) { ) : null} - - - - - - - - - - - - - + + + + + + + + + + + + + ); } From ac5c6ca0f00fd9a003302869de7fc2c88d3c0b94 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 21 Aug 2024 17:23:06 +0100 Subject: [PATCH 19/46] chore: bump 116 for testing staging with rewards fix --- electron/install.js | 2 +- package.json | 2 +- pyproject.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/electron/install.js b/electron/install.js index 2c3de2faa..efebf9180 100644 --- a/electron/install.js +++ b/electron/install.js @@ -14,7 +14,7 @@ const { paths } = require('./constants'); * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc115'; +const OlasMiddlewareVersion = '0.1.0rc116'; const path = require('path'); const { app } = require('electron'); diff --git a/package.json b/package.json index c5afe288e..5eaea98ea 100644 --- a/package.json +++ b/package.json @@ -58,5 +58,5 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc115" + "version": "0.1.0-rc116" } \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 9a58deb5d..db96e9913 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc115" +version = "0.1.0-rc116" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From 973b5d2884a805b8ec0e2c42488c831bd7557e37 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:51:47 +0100 Subject: [PATCH 20/46] Bump --- electron/install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/electron/install.js b/electron/install.js index efebf9180..a43856a9b 100644 --- a/electron/install.js +++ b/electron/install.js @@ -14,7 +14,7 @@ const { paths } = require('./constants'); * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc116'; +const OlasMiddlewareVersion = '0.1.0rc117'; const path = require('path'); const { app } = require('electron'); From 21a035e0d052cbfc53ef65c26dcd1908d00372a4 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:52:06 +0100 Subject: [PATCH 21/46] Bump --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5eaea98ea..b50e8fe5f 100644 --- a/package.json +++ b/package.json @@ -58,5 +58,5 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc116" -} \ No newline at end of file + "version": "0.1.0-rc117" +} From 219814e19127be0b3b945fab8cdec7eed53ab4c4 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:52:22 +0100 Subject: [PATCH 22/46] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index db96e9913..3c4bce6cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc116" +version = "0.1.0-rc117" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From da7690878628a572c5e234360bd5456740efcb6b Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 22 Aug 2024 15:51:03 +0200 Subject: [PATCH 23/46] fix: Add subgraph check of agent ID --- operate/services/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 120355c94..9a7fbffe8 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -974,7 +974,7 @@ def get_mint_tx_data( # pylint: disable=too-many-arguments ) .load_metadata() .verify_nft(nft=nft) - #.verify_service_dependencies(agent_id=agent_id) # TODO add this check once subgraph production indexes agent 25 + .verify_service_dependencies(agent_id=agent_id) .publish_metadata() ) instance = registry_contracts.service_manager.get_instance( From 6ccf85618707d54be434ee1fcfdc73a7537ce8b8 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 22 Aug 2024 16:14:05 +0200 Subject: [PATCH 24/46] chore: linters (black) --- operate/services/manage.py | 215 ++++++++++++++++++++++++----------- operate/services/protocol.py | 60 +++++----- operate/services/service.py | 56 +++++---- 3 files changed, 211 insertions(+), 120 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 6acf0b462..a87f9e57c 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -159,7 +159,9 @@ def load_or_create( service = Service.load(path=path) if service_template is not None: - service.update_user_params_from_template(service_template=service_template) + service.update_user_params_from_template( + service_template=service_template + ) return service @@ -410,7 +412,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to # TODO fix this os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc - os.environ["OPEN_AUTONOMY_SUBGRAPH_URL"] = "https://subgraph.autonolas.tech/subgraphs/name/autonolas-staging" + os.environ[ + "OPEN_AUTONOMY_SUBGRAPH_URL" + ] = "https://subgraph.autonolas.tech/subgraphs/name/autonolas-staging" current_agent_id = None if chain_data.token > -1: @@ -425,7 +429,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to if user_params.use_staking: staking_params = sftxb.get_staking_params( - staking_contract=STAKING[ledger_config.chain][user_params.staking_program_id], + staking_contract=STAKING[ledger_config.chain][ + user_params.staking_program_id + ], ) else: # TODO fix this - using pearl beta params staking_params = dict( @@ -434,7 +440,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to staking_token="0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", # nosec service_registry_token_utility="0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8", # nosec min_staking_deposit=20000000000000000000, - activity_checker="0x155547857680A6D51bebC5603397488988DEb1c8" # nosec + activity_checker="0x155547857680A6D51bebC5603397488988DEb1c8", # nosec ) if user_params.use_staking: @@ -448,7 +454,8 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to OnChainState.PRE_REGISTRATION, ): required_olas = ( - staking_params["min_staking_deposit"] + staking_params["min_staking_deposit"] # bond = staking + staking_params["min_staking_deposit"] + + staking_params["min_staking_deposit"] # bond = staking ) elif chain_data.on_chain_state == OnChainState.ACTIVE_REGISTRATION: required_olas = staking_params["min_staking_deposit"] @@ -470,13 +477,21 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to ) on_chain_hash = self._get_on_chain_hash(chain_config=chain_config) - is_first_mint = self._get_on_chain_state(chain_config=chain_config) == OnChainState.NON_EXISTENT + is_first_mint = ( + self._get_on_chain_state(chain_config=chain_config) + == OnChainState.NON_EXISTENT + ) is_update = ( (not is_first_mint) and (on_chain_hash is not None) - and (on_chain_hash != service.hash or current_agent_id != staking_params["agent_ids"][0]) + and ( + on_chain_hash != service.hash + or current_agent_id != staking_params["agent_ids"][0] + ) + ) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb ) - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) self.logger.info(f"{current_staking_program=}") self.logger.info(f"{user_params.staking_program_id=}") @@ -488,13 +503,13 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to self.logger.info(f"{is_update=}") if is_update: - self._terminate_service_on_chain_from_safe( - hash=hash, - chain_id=chain_id - ) + self._terminate_service_on_chain_from_safe(hash=hash, chain_id=chain_id) # Update service - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.PRE_REGISTRATION: + if ( + self._get_on_chain_state(chain_config=chain_config) + == OnChainState.PRE_REGISTRATION + ): self.logger.info("Updating service") receipt = ( sftxb.new_tx() @@ -533,10 +548,14 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() # Mint service - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.NON_EXISTENT: - + if ( + self._get_on_chain_state(chain_config=chain_config) + == OnChainState.NON_EXISTENT + ): if user_params.use_staking and not sftxb.staking_slots_available( - staking_contract=STAKING[ledger_config.chain][user_params.staking_program_id] + staking_contract=STAKING[ledger_config.chain][ + user_params.staking_program_id + ] ): raise ValueError("No staking slots available") @@ -578,7 +597,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.on_chain_state = OnChainState.PRE_REGISTRATION service.store() - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.PRE_REGISTRATION: + if ( + self._get_on_chain_state(chain_config=chain_config) + == OnChainState.PRE_REGISTRATION + ): cost_of_bond = staking_params["min_staking_deposit"] if user_params.use_staking: token_utility = staking_params["service_registry_token_utility"] @@ -628,7 +650,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.on_chain_state = OnChainState.ACTIVE_REGISTRATION service.store() - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.ACTIVE_REGISTRATION: + if ( + self._get_on_chain_state(chain_config=chain_config) + == OnChainState.ACTIVE_REGISTRATION + ): cost_of_bond = user_params.cost_of_bond if user_params.use_staking: token_utility = staking_params["service_registry_token_utility"] @@ -682,7 +707,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to chain_data.on_chain_state = OnChainState.FINISHED_REGISTRATION service.store() - if self._get_on_chain_state(chain_config=chain_config) == OnChainState.FINISHED_REGISTRATION: + if ( + self._get_on_chain_state(chain_config=chain_config) + == OnChainState.FINISHED_REGISTRATION + ): self.logger.info("Deploying service") reuse_multisig = True @@ -763,7 +791,9 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non chain_data.on_chain_state = OnChainState(info["service_state"]) # Determine if the service is staked in a known staking program - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb + ) is_staked = current_staking_program is not None can_unstake = False @@ -780,7 +810,9 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non # Unstake the service if applies if is_staked and can_unstake: - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.unstake_service_on_chain_from_safe( + hash=hash, chain_id=chain_id, staking_program_id=current_staking_program + ) if self._get_on_chain_state(chain_config) in ( OnChainState.ACTIVE_REGISTRATION, @@ -813,12 +845,18 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non service_id=chain_data.token, # noqa: E800 multisig=chain_data.multisig, # TODO this can be read from the registry owner_key=str( - self.keys_manager.get(key=current_safe_owners[0]).private_key # TODO allow multiple owners + self.keys_manager.get( + key=current_safe_owners[0] + ).private_key # TODO allow multiple owners ), # noqa: E800 - new_owner_address=wallet.safe if wallet.safe else wallet.crypto.address # TODO it should always be safe address + new_owner_address=wallet.safe + if wallet.safe + else wallet.crypto.address, # TODO it should always be safe address ) # noqa: E800 - def _get_current_staking_program(self, chain_data, ledger_config, sftxb) -> t.Optional[str]: + def _get_current_staking_program( + self, chain_data, ledger_config, sftxb + ) -> t.Optional[str]: if chain_data.token == NON_EXISTENT_TOKEN: return None @@ -859,7 +897,9 @@ def unbond_service_on_chain(self, hash: str) -> None: service.chain_data.on_chain_state = OnChainState.UNBONDED service.store() - def stake_service_on_chain(self, hash: str, chain_id: int, staking_program_id: str) -> None: + def stake_service_on_chain( + self, hash: str, chain_id: int, staking_program_id: str + ) -> None: """ Stake service on-chain @@ -888,16 +928,28 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc # Determine if the service is staked in a known staking program - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb + ) is_staked = current_staking_program is not None - current_staking_contract = STAKING[ledger_config.chain][current_staking_program] if is_staked else None + current_staking_contract = ( + STAKING[ledger_config.chain][current_staking_program] if is_staked else None + ) # perform the unstaking flow if necessary if is_staked: - can_unstake = sftxb.can_unstake(chain_config.chain_data.token, current_staking_contract) + can_unstake = sftxb.can_unstake( + chain_config.chain_data.token, current_staking_contract + ) if not chain_config.chain_data.user_params.use_staking and can_unstake: - self.logger.info(f"Use staking is set to false, but service {chain_config.chain_data.token} is staked and can be unstaked. Unstaking...") - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.logger.info( + f"Use staking is set to false, but service {chain_config.chain_data.token} is staked and can be unstaked. Unstaking..." + ) + self.unstake_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id, + staking_program_id=current_staking_program, + ) info = sftxb.info(token_id=chain_config.chain_data.token) chain_config.chain_data.on_chain_state = OnChainState(info["service_state"]) @@ -907,21 +959,43 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: ) if staking_state == StakingState.EVICTED and can_unstake: - self.logger.info(f"Service {chain_config.chain_data.token} has been evicted and can be unstaked. Unstaking...") - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.logger.info( + f"Service {chain_config.chain_data.token} has been evicted and can be unstaked. Unstaking..." + ) + self.unstake_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id, + staking_program_id=current_staking_program, + ) - if staking_state == StakingState.STAKED and can_unstake and not sftxb.staking_rewards_available(current_staking_contract): + if ( + staking_state == StakingState.STAKED + and can_unstake + and not sftxb.staking_rewards_available(current_staking_contract) + ): self.logger.info( f"There are no rewards available, service {chain_config.chain_data.token} " f"is already staked and can be unstaked. Unstaking..." ) - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.unstake_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id, + staking_program_id=current_staking_program, + ) - if staking_state == StakingState.STAKED and current_staking_program != target_staking_contract and can_unstake: + if ( + staking_state == StakingState.STAKED + and current_staking_program != target_staking_contract + and can_unstake + ): self.logger.info( f"{chain_config.chain_data.token} is staked in a different staking program. Unstaking..." ) - self.unstake_service_on_chain_from_safe(hash=hash, chain_id=chain_id, staking_program_id=current_staking_program) + self.unstake_service_on_chain_from_safe( + hash=hash, + chain_id=chain_id, + staking_program_id=current_staking_program, + ) staking_state = sftxb.staking_status( service_id=chain_config.chain_data.token, @@ -929,12 +1003,18 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: ) self.logger.info("Checking conditions to stake.") - staking_rewards_available = sftxb.staking_rewards_available(target_staking_contract) + staking_rewards_available = sftxb.staking_rewards_available( + target_staking_contract + ) staking_slots_available = sftxb.staking_slots_available(target_staking_contract) on_chain_state = self._get_on_chain_state(chain_config=chain_config) - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) - - self.logger.info(f"use_staking={chain_config.chain_data.user_params.use_staking}") + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb + ) + + self.logger.info( + f"use_staking={chain_config.chain_data.user_params.use_staking}" + ) self.logger.info(f"{staking_state=}") self.logger.info(f"{staking_rewards_available=}") self.logger.info(f"{staking_slots_available=}") @@ -943,19 +1023,17 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: self.logger.info(f"{target_staking_program=}") if ( - chain_config.chain_data.user_params.use_staking - and staking_state == StakingState.UNSTAKED - and staking_rewards_available - and staking_slots_available - and on_chain_state == OnChainState.DEPLOYED + chain_config.chain_data.user_params.use_staking + and staking_state == StakingState.UNSTAKED + and staking_rewards_available + and staking_slots_available + and on_chain_state == OnChainState.DEPLOYED ): self.logger.info(f"Approving staking: {chain_config.chain_data.token}") sftxb.new_tx().add( sftxb.get_staking_approval_data( service_id=chain_config.chain_data.token, - service_registry=CONTRACTS[ledger_config.chain][ - "service_registry" - ], + service_registry=CONTRACTS[ledger_config.chain]["service_registry"], staking_contract=target_staking_contract, ) ).settle() @@ -970,7 +1048,9 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: chain_config.chain_data.staked = True service.store() - current_staking_program = self._get_current_staking_program(chain_data, ledger_config, sftxb) + current_staking_program = self._get_current_staking_program( + chain_data, ledger_config, sftxb + ) self.logger.info(f"{target_staking_program=}") self.logger.info(f"{current_staking_program=}") @@ -1007,7 +1087,9 @@ def unstake_service_on_chain(self, hash: str) -> None: service.chain_data.staked = False service.store() - def unstake_service_on_chain_from_safe(self, hash: str, chain_id: str, staking_program_id: str) -> None: + def unstake_service_on_chain_from_safe( + self, hash: str, chain_id: str, staking_program_id: str + ) -> None: """ Unbond service on-chain @@ -1029,9 +1111,7 @@ def unstake_service_on_chain_from_safe(self, hash: str, chain_id: str, staking_p service_id=chain_data.token, staking_contract=STAKING[ledger_config.chain][staking_program_id], ) - self.logger.info( - f"Staking status for service {chain_data.token}: {state}" - ) + self.logger.info(f"Staking status for service {chain_data.token}: {state}") if state not in {StakingState.STAKED, StakingState.EVICTED}: self.logger.info("Cannot unstake service, it's not staked") chain_data.staked = False @@ -1065,10 +1145,11 @@ def fund_service( # pylint: disable=too-many-arguments ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data wallet = self.wallet_manager.load(ledger_config.type) - ledger_api = wallet.ledger_api(chain_type=ledger_config.chain, rpc=rpc if rpc else ledger_config.rpc) + ledger_api = wallet.ledger_api( + chain_type=ledger_config.chain, rpc=rpc if rpc else ledger_config.rpc + ) agent_fund_threshold = ( - agent_fund_threshold - or chain_data.user_params.fund_requirements.agent + agent_fund_threshold or chain_data.user_params.fund_requirements.agent ) for key in service.keys: @@ -1078,8 +1159,7 @@ def fund_service( # pylint: disable=too-many-arguments if agent_balance < agent_fund_threshold: self.logger.info("Funding agents") to_transfer = ( - agent_topup - or chain_data.user_params.fund_requirements.agent + agent_topup or chain_data.user_params.fund_requirements.agent ) self.logger.info(f"Transferring {to_transfer} units to {key.address}") wallet.transfer( @@ -1097,9 +1177,7 @@ def fund_service( # pylint: disable=too-many-arguments self.logger.info(f"Required balance: {safe_fund_treshold}") if safe_balance < safe_fund_treshold: self.logger.info("Funding safe") - to_transfer = ( - safe_topup or chain_data.user_params.fund_requirements.safe - ) + to_transfer = safe_topup or chain_data.user_params.fund_requirements.safe self.logger.info( f"Transferring {to_transfer} units to {chain_data.multisig}" ) @@ -1177,12 +1255,9 @@ def update_service( """Update a service.""" self.logger.info("-----Entering update local service-----") - old_service = self.load_or_create( - hash=old_hash - ) + old_service = self.load_or_create(hash=old_hash) new_service = self.load_or_create( - hash=new_hash, - service_template=service_template + hash=new_hash, service_template=service_template ) new_service.keys = old_service.keys # new_Service.home_chain_id = old_service.home_chain_id @@ -1193,9 +1268,13 @@ def update_service( new_service.chain_configs = {} for chain_id, config in old_service.chain_configs.items(): - new_service.chain_configs[chain_id] = config + new_service.chain_configs[chain_id] = config if service_template: - new_service.chain_configs[chain_id].chain_data.user_params = OnChainUserParams.from_json(service_template["configurations"][chain_id]) + new_service.chain_configs[ + chain_id + ].chain_data.user_params = OnChainUserParams.from_json( + service_template["configurations"][chain_id] + ) new_service.store() diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 9a7fbffe8..f58f5b921 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -242,7 +242,7 @@ def service_info(self, staking_contract: str, service_id: int) -> dict: staking_contract, service_id, ).get("data") - + def agent_ids(self, staking_contract: str) -> t.List[int]: instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, @@ -536,7 +536,6 @@ def owner_of(self, token_id: int) -> str: chain_type=self.chain_type ) - def info(self, token_id: int) -> t.Dict: """Get service info.""" self._patch() @@ -574,7 +573,6 @@ def info(self, token_id: int) -> t.Dict: instances=instances, ) - def get_service_safe_owners(self, service_id: int) -> t.List[str]: """Get list of owners.""" ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects( @@ -599,13 +597,8 @@ def get_service_safe_owners(self, service_id: int) -> t.List[str]: contract_address=multisig_address, ).get("owners", []) - def swap( # pylint: disable=too-many-arguments,too-many-locals - self, - service_id: int, - multisig: str, - owner_key: str, - new_owner_address: str + self, service_id: int, multisig: str, owner_key: str, new_owner_address: str ) -> None: """Swap safe owner.""" logging.info(f"Swapping safe for service {service_id} [{multisig}]...") @@ -634,9 +627,7 @@ def swap( # pylint: disable=too-many-arguments,too-many-locals ledger_api=manager.ledger_api, contract_address=multisig, old_owner=manager.ledger_api.api.to_checksum_address(owner_to_swap), - new_owner=manager.ledger_api.api.to_checksum_address( - new_owner_address - ), + new_owner=manager.ledger_api.api.to_checksum_address(new_owner_address), ).get("data") multisend_txs.append( { @@ -720,6 +711,7 @@ def staking_rewards_available(self, staking_contract: str) -> bool: ) return available_rewards > 0 + class OnChainManager(_ChainUtil): """On chain service management.""" @@ -1003,9 +995,9 @@ def get_mint_tx_data( # pylint: disable=too-many-arguments [agent_id], [[number_of_slots, cost_of_bond]], threshold, - update_token + update_token, ], - ) + ) return { "to": self.contracts["service_manager"], @@ -1139,7 +1131,11 @@ def get_deploy_data_from_safe( ) approve_hash_message = None if reuse_multisig: - _deployment_payload, approve_hash_message, error = get_reuse_multisig_from_safe_payload( + ( + _deployment_payload, + approve_hash_message, + error, + ) = get_reuse_multisig_from_safe_payload( ledger_api=self.ledger_api, chain_type=self.chain_type, service_id=service_id, @@ -1334,7 +1330,7 @@ def get_staking_params(self, staking_contract: str) -> t.Dict: staking_token=staking_token, service_registry_token_utility=service_registry_token_utility, min_staking_deposit=min_staking_deposit, - activity_checker=activity_checker + activity_checker=activity_checker, ) def can_unstake(self, service_id: int, staking_contract: str) -> bool: @@ -1358,26 +1354,25 @@ def get_swap_data(self, service_id: int, multisig: str, owner_key: str) -> t.Dic raise NotImplementedError() - def get_packed_signature_for_approved_hash(owners: t.Tuple[str]) -> bytes: - """Get the packed signatures.""" - sorted_owners = sorted(owners, key=str.lower) - signatures = b'' - for owner in sorted_owners: - # Convert address to bytes and ensure it is 32 bytes long (left-padded with zeros) - r_bytes = to_bytes(hexstr=owner[2:].rjust(64, '0')) + """Get the packed signatures.""" + sorted_owners = sorted(owners, key=str.lower) + signatures = b"" + for owner in sorted_owners: + # Convert address to bytes and ensure it is 32 bytes long (left-padded with zeros) + r_bytes = to_bytes(hexstr=owner[2:].rjust(64, "0")) - # `s` as 32 zero bytes - s_bytes = b'\x00' * 32 + # `s` as 32 zero bytes + s_bytes = b"\x00" * 32 - # `v` as a single byte - v_bytes = to_bytes(1) + # `v` as a single byte + v_bytes = to_bytes(1) - # Concatenate r, s, and v to form the packed signature - packed_signature = r_bytes + s_bytes + v_bytes - signatures += packed_signature + # Concatenate r, s, and v to form the packed signature + packed_signature = r_bytes + s_bytes + v_bytes + signatures += packed_signature - return signatures + return signatures def get_reuse_multisig_from_safe_payload( # pylint: disable=too-many-locals @@ -1477,7 +1472,7 @@ def get_reuse_multisig_from_safe_payload( # pylint: disable=too-many-locals contract_address=multisend_address, txs=txs, ) - signature_bytes = get_packed_signature_for_approved_hash(owners=(master_safe, )) + signature_bytes = get_packed_signature_for_approved_hash(owners=(master_safe,)) safe_tx_hash = registry_contracts.gnosis_safe.get_raw_safe_transaction_hash( ledger_api=ledger_api, @@ -1517,4 +1512,3 @@ def get_reuse_multisig_from_safe_payload( # pylint: disable=too-many-locals ) payload = multisig_address + safe_exec_data[2:] return payload, approve_hash_message, None - diff --git a/operate/services/service.py b/operate/services/service.py index ea6c563ca..10aa4d3a8 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -656,15 +656,19 @@ class Service(LocalResource): @classmethod def migrate_format(cls, path: Path) -> None: """Migrate the JSON file format if needed.""" - file_path = path / Service._file if Service._file is not None and path.name != Service._file else path - - with open(file_path, 'r', encoding='utf-8') as file: + file_path = ( + path / Service._file + if Service._file is not None and path.name != Service._file + else path + ) + + with open(file_path, "r", encoding="utf-8") as file: data = json.load(file) - - if 'version' in data: + + if "version" in data: # Data is already in the new format return - + # Migrate from old format to new format new_data = { "version": 2, @@ -676,30 +680,42 @@ def migrate_format(cls, path: Path) -> None: "ledger_config": { "rpc": data.get("ledger_config", {}).get("rpc"), "type": data.get("ledger_config", {}).get("type"), - "chain": data.get("ledger_config", {}).get("chain") + "chain": data.get("ledger_config", {}).get("chain"), }, "chain_data": { "instances": data.get("chain_data", {}).get("instances", []), "token": data.get("chain_data", {}).get("token"), "multisig": data.get("chain_data", {}).get("multisig"), "staked": data.get("chain_data", {}).get("staked", False), - "on_chain_state": data.get("chain_data", {}).get("on_chain_state", 3), + "on_chain_state": data.get("chain_data", {}).get( + "on_chain_state", 3 + ), "user_params": { "staking_program_id": "pearl_alpha", - "nft": data.get("chain_data", {}).get("user_params", {}).get("nft"), - "threshold": data.get("chain_data", {}).get("user_params", {}).get("threshold"), - "use_staking": data.get("chain_data", {}).get("user_params", {}).get("use_staking"), - "cost_of_bond": data.get("chain_data", {}).get("user_params", {}).get("cost_of_bond"), - "fund_requirements": data.get("chain_data", {}).get("user_params", {}).get("fund_requirements", {}) - } - } + "nft": data.get("chain_data", {}) + .get("user_params", {}) + .get("nft"), + "threshold": data.get("chain_data", {}) + .get("user_params", {}) + .get("threshold"), + "use_staking": data.get("chain_data", {}) + .get("user_params", {}) + .get("use_staking"), + "cost_of_bond": data.get("chain_data", {}) + .get("user_params", {}) + .get("cost_of_bond"), + "fund_requirements": data.get("chain_data", {}) + .get("user_params", {}) + .get("fund_requirements", {}), + }, + }, } }, "service_path": data.get("service_path", ""), - "name": data.get("name", "") + "name": data.get("name", ""), } - - with open(file_path, 'w', encoding='utf-8') as file: + + with open(file_path, "w", encoding="utf-8") as file: json.dump(new_data, file, indent=2) @classmethod @@ -781,7 +797,9 @@ def update_user_params_from_template(self, service_template: ServiceTemplate): """Update user params from template.""" for chain, config in service_template["configurations"].items(): for chain, config in service_template["configurations"].items(): - self.chain_configs[chain].chain_data.user_params = OnChainUserParams.from_json(config) + self.chain_configs[ + chain + ].chain_data.user_params = OnChainUserParams.from_json(config) self.store() From bcd3a1308325eef9d9e78770072d9d0defae2259 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 22 Aug 2024 16:36:13 +0200 Subject: [PATCH 25/46] fix: linters --- operate/cli.py | 7 ++++--- operate/services/manage.py | 33 +++++++++++++++++---------------- operate/services/protocol.py | 6 ++++++ 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index 7d5285d13..99cabe0f1 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -530,8 +530,8 @@ async def _create_services(request: Request) -> JSONResponse: if template.get("deploy", False): def _fn() -> None: + # deploy_service_onchain_from_safe includes stake_service_on_chain_from_safe manager.deploy_service_onchain_from_safe(hash=service.hash) - # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done inside deploy_service_onchain manager.fund_service(hash=service.hash) manager.deploy_service_locally(hash=service.hash) @@ -556,8 +556,9 @@ async def _update_services(request: Request) -> JSONResponse: ) if template.get("deploy", False): manager = operate.service_manager() + + # deploy_service_onchain_from_safe includes stake_service_on_chain_from_safe manager.deploy_service_onchain_from_safe(hash=service.hash) - # manager.stake_service_on_chain_from_safe(hash=service.hash) # Done in deploy_service_onchain_from_safe manager.fund_service(hash=service.hash) manager.deploy_service_locally(hash=service.hash) schedule_funding_job(service=service.hash) @@ -675,7 +676,7 @@ async def _start_service_locally(request: Request) -> JSONResponse: def _fn() -> None: manager.deploy_service_onchain(hash=service) - # manager.stake_service_on_chain(hash=service) + manager.stake_service_on_chain(hash=service) manager.fund_service(hash=service) manager.deploy_service_locally(hash=service, force=True) diff --git a/operate/services/manage.py b/operate/services/manage.py index a87f9e57c..8459bfa2f 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -186,22 +186,21 @@ def load_or_create( return service - def _get_on_chain_state(self, chain_config: ChainConfig) -> OnChainState: + def _get_on_chain_state(self, service: Service, chain_id: str) -> OnChainState: + chain_config = service.chain_configs[chain_id] chain_data = chain_config.chain_data ledger_config = chain_config.ledger_config if chain_data.token == NON_EXISTENT_TOKEN: service_state = OnChainState.NON_EXISTENT chain_data.on_chain_state = service_state - # TODO save service state - # service.store() + service.store() return service_state sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) info = sftxb.info(token_id=chain_data.token) service_state = OnChainState(info["service_state"]) chain_data.on_chain_state = service_state - # TODO save service state - # service.store() + service.store() return service_state def _get_on_chain_hash(self, chain_config: ChainConfig) -> t.Optional[str]: @@ -478,7 +477,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to on_chain_hash = self._get_on_chain_hash(chain_config=chain_config) is_first_mint = ( - self._get_on_chain_state(chain_config=chain_config) + self._get_on_chain_state(service=service, chain_id=chain_id) == OnChainState.NON_EXISTENT ) is_update = ( @@ -507,7 +506,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to # Update service if ( - self._get_on_chain_state(chain_config=chain_config) + self._get_on_chain_state(service=service, chain_id=chain_id) == OnChainState.PRE_REGISTRATION ): self.logger.info("Updating service") @@ -549,7 +548,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to # Mint service if ( - self._get_on_chain_state(chain_config=chain_config) + self._get_on_chain_state(service=service, chain_id=chain_id) == OnChainState.NON_EXISTENT ): if user_params.use_staking and not sftxb.staking_slots_available( @@ -598,7 +597,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() if ( - self._get_on_chain_state(chain_config=chain_config) + self._get_on_chain_state(service=service, chain_id=chain_id) == OnChainState.PRE_REGISTRATION ): cost_of_bond = staking_params["min_staking_deposit"] @@ -651,7 +650,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() if ( - self._get_on_chain_state(chain_config=chain_config) + self._get_on_chain_state(service=service, chain_id=chain_id) == OnChainState.ACTIVE_REGISTRATION ): cost_of_bond = user_params.cost_of_bond @@ -708,7 +707,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() if ( - self._get_on_chain_state(chain_config=chain_config) + self._get_on_chain_state(service=service, chain_id=chain_id) == OnChainState.FINISHED_REGISTRATION ): self.logger.info("Deploying service") @@ -1007,7 +1006,7 @@ def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: target_staking_contract ) staking_slots_available = sftxb.staking_slots_available(target_staking_contract) - on_chain_state = self._get_on_chain_state(chain_config=chain_config) + on_chain_state = self._get_on_chain_state(service=service, chain_id=chain_id) current_staking_program = self._get_current_staking_program( chain_data, ledger_config, sftxb ) @@ -1260,12 +1259,14 @@ def update_service( hash=new_hash, service_template=service_template ) new_service.keys = old_service.keys - # new_Service.home_chain_id = old_service.home_chain_id - # TODO - Ensure this works as expected - New service must copy all chain_data from old service, - # but if service_template is not None, it must copy the user_params - # passed in the service_template and copy the remaining attributes from old_service. + # TODO Ensure this is as intended. + new_service.home_chain_id = old_service.home_chain_id + # new_service must copy all chain_data from old_service. + # Additionally, if service_template is not None, it must overwrite + # the user_params on all chain_data by the values passed through the + # service_template. new_service.chain_configs = {} for chain_id, config in old_service.chain_configs.items(): new_service.chain_configs[chain_id] = config diff --git a/operate/services/protocol.py b/operate/services/protocol.py index f58f5b921..f7edf4eff 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -244,6 +244,7 @@ def service_info(self, staking_contract: str, service_id: int) -> dict: ).get("data") def agent_ids(self, staking_contract: str) -> t.List[int]: + """Get the agent IDs for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -251,6 +252,7 @@ def agent_ids(self, staking_contract: str) -> t.List[int]: return instance.functions.getAgentIds().call() def service_registry(self, staking_contract: str) -> str: + """Get the service registry address for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -258,6 +260,7 @@ def service_registry(self, staking_contract: str) -> str: return instance.functions.serviceRegistry().call() def staking_token(self, staking_contract: str) -> str: + """Get the staking token address for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -265,6 +268,7 @@ def staking_token(self, staking_contract: str) -> str: return instance.functions.stakingToken().call() def service_registry_token_utility(self, staking_contract: str) -> str: + """Get the service registry token utility address for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -272,6 +276,7 @@ def service_registry_token_utility(self, staking_contract: str) -> str: return instance.functions.serviceRegistryTokenUtility().call() def min_staking_deposit(self, staking_contract: str) -> str: + """Get the minimum staking deposit for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, @@ -279,6 +284,7 @@ def min_staking_deposit(self, staking_contract: str) -> str: return instance.functions.minStakingDeposit().call() def activity_checker(self, staking_contract: str) -> str: + """Get the activity checker address for the specified staking contract""" instance = self.staking_ctr.get_instance( ledger_api=self.ledger_api, contract_address=staking_contract, From 51477779bdd06fde8209b72fecb88a638e428dc7 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 22 Aug 2024 18:43:21 +0200 Subject: [PATCH 26/46] fix: linters --- operate/services/manage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 8459bfa2f..7c6d2b5a3 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -433,7 +433,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to ], ) else: # TODO fix this - using pearl beta params - staking_params = dict( + staking_params = dict( # nosec agent_ids=[25], service_registry="0x9338b5153AE39BB89f50468E608eD9d764B755fD", # nosec staking_token="0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", # nosec From 1efa08bbb998b733e726f71b058dbf442634104e Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 22 Aug 2024 19:22:23 +0200 Subject: [PATCH 27/46] chore: linters --- operate/services/manage.py | 24 +++++++++++++++--------- operate/services/protocol.py | 7 ------- operate/services/service.py | 18 +++++++++--------- 3 files changed, 24 insertions(+), 25 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 7c6d2b5a3..81c7dd78c 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -767,7 +767,9 @@ def terminate_service_on_chain(self, hash: str) -> None: service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED service.store() - def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: + def _terminate_service_on_chain_from_safe( + self, hash: str, chain_id: str + ) -> None: # pylint: disable=too-many-locals """ Terminate service on-chain @@ -813,7 +815,7 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non hash=hash, chain_id=chain_id, staking_program_id=current_staking_program ) - if self._get_on_chain_state(chain_config) in ( + if self._get_on_chain_state(service=service, chain_id=chain_id) in ( OnChainState.ACTIVE_REGISTRATION, OnChainState.FINISHED_REGISTRATION, OnChainState.DEPLOYED, @@ -825,7 +827,10 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non ) ).settle() - if self._get_on_chain_state(chain_config) == OnChainState.TERMINATED_BONDED: + if ( + self._get_on_chain_state(service=service, chain_id=chain_id) + == OnChainState.TERMINATED_BONDED + ): self.logger.info("Unbonding service") sftxb.new_tx().add( sftxb.get_unbond_data( @@ -853,8 +858,9 @@ def _terminate_service_on_chain_from_safe(self, hash: str, chain_id: str) -> Non else wallet.crypto.address, # TODO it should always be safe address ) # noqa: E800 + @staticmethod def _get_current_staking_program( - self, chain_data, ledger_config, sftxb + chain_data, ledger_config, sftxb ) -> t.Optional[str]: if chain_data.token == NON_EXISTENT_TOKEN: return None @@ -896,9 +902,7 @@ def unbond_service_on_chain(self, hash: str) -> None: service.chain_data.on_chain_state = OnChainState.UNBONDED service.store() - def stake_service_on_chain( - self, hash: str, chain_id: int, staking_program_id: str - ) -> None: + def stake_service_on_chain(self, hash: str) -> None: """ Stake service on-chain @@ -906,7 +910,9 @@ def stake_service_on_chain( """ raise NotImplementedError - def stake_service_on_chain_from_safe(self, hash: str, chain_id: str) -> None: + def stake_service_on_chain_from_safe( + self, hash: str, chain_id: str + ) -> None: # pylint: disable=too-many-statements,too-many-locals """ Stake service on-chain @@ -1127,7 +1133,7 @@ def unstake_service_on_chain_from_safe( chain_data.staked = False service.store() - def fund_service( # pylint: disable=too-many-arguments + def fund_service( # pylint: disable=too-many-arguments,too-many-locals self, hash: str, rpc: t.Optional[str] = None, diff --git a/operate/services/protocol.py b/operate/services/protocol.py index f7edf4eff..4c97a51c9 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -535,13 +535,6 @@ def ledger_api(self) -> LedgerApi: ) return ledger_api - def owner_of(self, token_id: int) -> str: - """Get owner of a service.""" - self._patch() - ledger_api, _ = OnChainHelper.get_ledger_and_crypto_objects( - chain_type=self.chain_type - ) - def info(self, token_id: int) -> t.Dict: """Get service info.""" self._patch() diff --git a/operate/services/service.py b/operate/services/service.py index 10aa4d3a8..d164e29e3 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -82,12 +82,13 @@ ) +# pylint: disable=no-member,redefined-builtin,too-many-instance-attributes + SAFE_CONTRACT_ADDRESS = "safe_contract_address" ALL_PARTICIPANTS = "all_participants" CONSENSUS_THRESHOLD = "consensus_threshold" DELETE_PREFIX = "delete_" - -# pylint: disable=no-member,redefined-builtin,too-many-instance-attributes +SERVICE_CONFIG_VERSION = 2 DUMMY_MULTISIG = "0xm" NON_EXISTENT_TOKEN = -1 @@ -238,7 +239,7 @@ def __init__(self, path: Path) -> None: self.path = path self.config = load_service_config(service_path=path) - def ledger_configs(self) -> "LedgerConfigs": + def ledger_configs(self) -> LedgerConfigs: """Get ledger configs.""" ledger_configs = {} for override in self.config.overrides: @@ -741,7 +742,7 @@ def deployment(self) -> Deployment: return t.cast(Deployment, self._deployment) @staticmethod - def new( + def new( # pylint: disable=too-many-locals hash: str, keys: Keys, service_template: ServiceTemplate, @@ -781,7 +782,7 @@ def new( ) service = Service( - version=2, # TODO implement in appropriate place + version=SERVICE_CONFIG_VERSION, name=service_yaml["author"] + "/" + service_yaml["name"], hash=service_template["hash"], keys=keys, @@ -796,10 +797,9 @@ def new( def update_user_params_from_template(self, service_template: ServiceTemplate): """Update user params from template.""" for chain, config in service_template["configurations"].items(): - for chain, config in service_template["configurations"].items(): - self.chain_configs[ - chain - ].chain_data.user_params = OnChainUserParams.from_json(config) + self.chain_configs[ + chain + ].chain_data.user_params = OnChainUserParams.from_json(config) self.store() From 9a9906b5de47b11d0f090984551cab5c6680555e Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 22 Aug 2024 19:26:27 +0200 Subject: [PATCH 28/46] chore: linters --- operate/services/manage.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 81c7dd78c..e6393e664 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -767,9 +767,9 @@ def terminate_service_on_chain(self, hash: str) -> None: service.chain_data.on_chain_state = OnChainState.TERMINATED_BONDED service.store() - def _terminate_service_on_chain_from_safe( + def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals self, hash: str, chain_id: str - ) -> None: # pylint: disable=too-many-locals + ) -> None: """ Terminate service on-chain @@ -910,9 +910,9 @@ def stake_service_on_chain(self, hash: str) -> None: """ raise NotImplementedError - def stake_service_on_chain_from_safe( + def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too-many-locals self, hash: str, chain_id: str - ) -> None: # pylint: disable=too-many-statements,too-many-locals + ) -> None: """ Stake service on-chain From 0610fce306e754332f1ca35ffc3eddb68a7aa30e Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 22 Aug 2024 19:45:31 +0200 Subject: [PATCH 29/46] chore: linters --- operate/services/service.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/operate/services/service.py b/operate/services/service.py index d164e29e3..2107cce56 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -417,7 +417,8 @@ def _build_docker( builder.deplopyment_type = DockerComposeGenerator.deployment_type builder.try_update_abci_connection_params() - home_chain_data = service.chain_configs[service.home_chain_id] + home_chain_data = service.chain_configs[service.home_chain_id].chain_data + home_chain_ledger_config = service.chain_configs[service.home_chain_id].ledger_config builder.try_update_runtime_params( multisig_address=home_chain_data.multisig, agent_instances=home_chain_data.instances, @@ -426,8 +427,8 @@ def _build_docker( ) # TODO: Support for multiledger builder.try_update_ledger_params( - chain=LedgerType(service.ledger_config.type).name.lower(), - address=service.ledger_config.rpc, + chain=LedgerType(home_chain_ledger_config.type).name.lower(), + address=home_chain_ledger_config.rpc, ) # build deployment @@ -773,7 +774,7 @@ def new( # pylint: disable=too-many-locals multisig=DUMMY_MULTISIG, staked=False, on_chain_state=OnChainState.NON_EXISTENT, - user_params=OnChainUserParams.from_json(config), + user_params=OnChainUserParams.from_json(config), # type: ignore ) chain_configs[chain] = ChainConfig( @@ -794,12 +795,12 @@ def new( # pylint: disable=too-many-locals service.store() return service - def update_user_params_from_template(self, service_template: ServiceTemplate): + def update_user_params_from_template(self, service_template: ServiceTemplate) -> None: """Update user params from template.""" for chain, config in service_template["configurations"].items(): self.chain_configs[ chain - ].chain_data.user_params = OnChainUserParams.from_json(config) + ].chain_data.user_params = OnChainUserParams.from_json(config) # type: ignore self.store() From 092e655350dbe9b6fda42ce816b40f8c43a6a2d5 Mon Sep 17 00:00:00 2001 From: Ardian Date: Thu, 22 Aug 2024 21:01:46 +0200 Subject: [PATCH 30/46] chore: ignore missing import for `eth_utils` --- tox.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tox.ini b/tox.ini index b7de2caf0..88426bd93 100644 --- a/tox.ini +++ b/tox.ini @@ -215,3 +215,6 @@ ignore_missing_imports = True [mypy-psutil.*] ignore_missing_imports = True + +[mypy-eth_utils.*] +ignore_missing_imports = True From 6c3cb7cbfec52578a6a90a8c336e815263716356 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 28 Aug 2024 11:07:38 +0200 Subject: [PATCH 31/46] chore: fix fund before swap transaction --- operate/services/manage.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/operate/services/manage.py b/operate/services/manage.py index e6393e664..6ea44db92 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -476,6 +476,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to ) on_chain_hash = self._get_on_chain_hash(chain_config=chain_config) + current_agent_bond = staking_params["min_staking_deposit"] # TODO fixme, read from service registry token utility contract is_first_mint = ( self._get_on_chain_state(service=service, chain_id=chain_id) == OnChainState.NON_EXISTENT @@ -486,6 +487,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to and ( on_chain_hash != service.hash or current_agent_id != staking_params["agent_ids"][0] + or current_agent_bond != staking_params["min_staking_deposit"] ) ) current_staking_program = self._get_current_staking_program( @@ -845,6 +847,16 @@ def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals if counter_current_safe_owners == counter_instances: self.logger.info("Swapping Safe owners") + + self.fund_service( + hash=hash, + rpc=ledger_config.rpc, + agent_topup=chain_data.user_params.fund_requirements.agent, + agent_fund_threshold=chain_data.user_params.fund_requirements.agent, + safe_topup=0, + safe_fund_treshold=0, + ) + sftxb.swap( # noqa: E800 service_id=chain_data.token, # noqa: E800 multisig=chain_data.multisig, # TODO this can be read from the registry From 75a9ccfc76a309f0409b4f26eaa6a0f9e270b6e7 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 28 Aug 2024 12:44:08 +0100 Subject: [PATCH 32/46] fix: required staking balance calculations --- .../StakingContractSection/index.tsx | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 363f7ce55..edfe91959 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -65,10 +65,10 @@ export const StakingContractSection = ({ const { setMigrationModalOpen } = useModals(); const { activeStakingProgram, defaultStakingProgram, updateStakingProgram } = useStakingProgram(); - const { stakingContractInfoRecord } = useStakingContractInfo(); const { token } = useToken(); - const { totalOlasBalance, isBalanceLoaded } = useBalance(); - const { isServiceStakedForMinimumDuration } = useStakingContractInfo(); + const { safeBalance, totalOlasStakedBalance, isBalanceLoaded } = useBalance(); + const { isServiceStakedForMinimumDuration, stakingContractInfoRecord } = + useStakingContractInfo(); const stakingContractInfoForStakingProgram = stakingContractInfoRecord?.[stakingProgram]; @@ -87,10 +87,15 @@ export const StakingContractSection = ({ ); const hasEnoughOlasToMigrate = useMemo(() => { - if (totalOlasBalance === undefined) return false; - if (!minimumOlasRequiredToMigrate) return false; - return totalOlasBalance >= minimumOlasRequiredToMigrate; - }, [minimumOlasRequiredToMigrate, totalOlasBalance]); + if (safeBalance?.OLAS === undefined || totalOlasStakedBalance === undefined) + return false; + + const balanceForMigration = safeBalance.OLAS + totalOlasStakedBalance; + + if (minimumOlasRequiredToMigrate === undefined) return false; + + return balanceForMigration >= minimumOlasRequiredToMigrate; + }, [minimumOlasRequiredToMigrate, safeBalance?.OLAS, totalOlasStakedBalance]); const hasEnoughSlots = stakingContractInfoForStakingProgram?.maxNumServices && @@ -167,6 +172,7 @@ export const StakingContractSection = ({ isBalanceLoaded, isSelected, isServiceStakedForMinimumDuration, + minimumOlasRequiredToMigrate, serviceStatus, ]); @@ -181,7 +187,11 @@ export const StakingContractSection = ({ if (!hasEnoughOlasToMigrate) { return ( - + ); } @@ -191,10 +201,12 @@ export const StakingContractSection = ({ }, [ isSelected, isBalanceLoaded, - totalOlasBalance, hasEnoughSlots, hasEnoughOlasToMigrate, isAppVersionCompatible, + safeBalance?.OLAS, + totalOlasStakedBalance, + minimumOlasRequiredToMigrate, ]); const contractTagStatus = useMemo(() => { From 20114179012b90d6b0279ea2fe11085721fd7ceb Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 28 Aug 2024 12:44:19 +0100 Subject: [PATCH 33/46] refactor: update copy as per figma --- .../StakingContractSection/alerts.tsx | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx b/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx index f2c1cf6cd..bee80cbcb 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx @@ -6,28 +6,38 @@ import { UNICODE_SYMBOLS } from '@/constants/symbols'; const { Text } = Typography; export const AlertInsufficientMigrationFunds = ({ - totalOlasBalance, + masterSafeOlasBalance, + stakedOlasBalance, + totalOlasRequiredForStaking, }: { - totalOlasBalance: number; -}) => ( - - - Insufficient amount of funds to switch - + masterSafeOlasBalance?: number; + stakedOlasBalance?: number; + totalOlasRequiredForStaking: number; +}) => { + const requiredOlasDeposit = + stakedOlasBalance !== undefined && + masterSafeOlasBalance !== undefined && + totalOlasRequiredForStaking - (stakedOlasBalance + masterSafeOlasBalance); - Add funds to your account to meet the program requirements. - - Your current OLAS balance:{' '} - {totalOlasBalance} OLAS - - - } - /> -); + return ( + + + Additional {requiredOlasDeposit} OLAS are required to switch + + + + Add {requiredOlasDeposit} OLAS to your account to + meet the contract requirements and be able to switch. + + + } + /> + ); +}; export const AlertNoSlots = () => ( Date: Wed, 28 Aug 2024 12:51:51 +0100 Subject: [PATCH 34/46] refactor: ensure not undefined earlier --- .../ManageStakingPage/StakingContractSection/alerts.tsx | 6 ++---- .../ManageStakingPage/StakingContractSection/index.tsx | 8 ++++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx b/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx index bee80cbcb..6aeb6471d 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/alerts.tsx @@ -10,13 +10,11 @@ export const AlertInsufficientMigrationFunds = ({ stakedOlasBalance, totalOlasRequiredForStaking, }: { - masterSafeOlasBalance?: number; - stakedOlasBalance?: number; + masterSafeOlasBalance: number; + stakedOlasBalance: number; totalOlasRequiredForStaking: number; }) => { const requiredOlasDeposit = - stakedOlasBalance !== undefined && - masterSafeOlasBalance !== undefined && totalOlasRequiredForStaking - (stakedOlasBalance + masterSafeOlasBalance); return ( diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index edfe91959..9acfc4c39 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -185,10 +185,14 @@ export const StakingContractSection = ({ return ; } - if (!hasEnoughOlasToMigrate) { + if ( + !hasEnoughOlasToMigrate && + safeBalance?.OLAS !== undefined && + totalOlasStakedBalance !== undefined + ) { return ( From 2c58a2161b3252a1ee09a6b8d1a900c019557daa Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 28 Aug 2024 16:13:35 +0200 Subject: [PATCH 35/46] chore: minor fixes --- operate/services/manage.py | 4 ++-- operate/services/protocol.py | 7 +++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 6ea44db92..cb4cb5e37 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -846,8 +846,7 @@ def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals counter_instances = Counter(s.lower() for s in instances) if counter_current_safe_owners == counter_instances: - self.logger.info("Swapping Safe owners") - + self.logger.info("Service funded for safe swap") self.fund_service( hash=hash, rpc=ledger_config.rpc, @@ -857,6 +856,7 @@ def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals safe_fund_treshold=0, ) + self.logger.info("Swapping Safe owners") sftxb.swap( # noqa: E800 service_id=chain_data.token, # noqa: E800 multisig=chain_data.multisig, # TODO this can be read from the registry diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 4c97a51c9..6c52fb069 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -23,7 +23,6 @@ import contextlib import io import json -import logging import tempfile import time import typing as t @@ -600,7 +599,6 @@ def swap( # pylint: disable=too-many-arguments,too-many-locals self, service_id: int, multisig: str, owner_key: str, new_owner_address: str ) -> None: """Swap safe owner.""" - logging.info(f"Swapping safe for service {service_id} [{multisig}]...") self._patch() manager = ServiceManager( service_id=service_id, @@ -710,6 +708,11 @@ def staking_rewards_available(self, staking_contract: str) -> bool: ) return available_rewards > 0 + # def get_agent_bond(self, staking_contract: str) -> int: + # self._patch() + + + class OnChainManager(_ChainUtil): """On chain service management.""" From 9317ea38a0aaa6332198c35800ce3fc4b00e91a1 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 28 Aug 2024 16:15:44 +0200 Subject: [PATCH 36/46] fix: linters --- operate/services/manage.py | 4 +++- operate/services/protocol.py | 2 -- operate/services/service.py | 12 +++++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index cb4cb5e37..71f317b49 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -476,7 +476,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to ) on_chain_hash = self._get_on_chain_hash(chain_config=chain_config) - current_agent_bond = staking_params["min_staking_deposit"] # TODO fixme, read from service registry token utility contract + current_agent_bond = staking_params[ + "min_staking_deposit" + ] # TODO fixme, read from service registry token utility contract is_first_mint = ( self._get_on_chain_state(service=service, chain_id=chain_id) == OnChainState.NON_EXISTENT diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 6c52fb069..709e65576 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -710,8 +710,6 @@ def staking_rewards_available(self, staking_contract: str) -> bool: # def get_agent_bond(self, staking_contract: str) -> int: # self._patch() - - class OnChainManager(_ChainUtil): diff --git a/operate/services/service.py b/operate/services/service.py index 2107cce56..675a526f1 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -418,7 +418,9 @@ def _build_docker( builder.try_update_abci_connection_params() home_chain_data = service.chain_configs[service.home_chain_id].chain_data - home_chain_ledger_config = service.chain_configs[service.home_chain_id].ledger_config + home_chain_ledger_config = service.chain_configs[ + service.home_chain_id + ].ledger_config builder.try_update_runtime_params( multisig_address=home_chain_data.multisig, agent_instances=home_chain_data.instances, @@ -795,12 +797,16 @@ def new( # pylint: disable=too-many-locals service.store() return service - def update_user_params_from_template(self, service_template: ServiceTemplate) -> None: + def update_user_params_from_template( + self, service_template: ServiceTemplate + ) -> None: """Update user params from template.""" for chain, config in service_template["configurations"].items(): self.chain_configs[ chain - ].chain_data.user_params = OnChainUserParams.from_json(config) # type: ignore + ].chain_data.user_params = OnChainUserParams.from_json( + config + ) # type: ignore self.store() From ce45d60e86ce395dbc630e9cdbc4653e07e3d672 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 28 Aug 2024 16:22:07 +0200 Subject: [PATCH 37/46] chore: minor fix --- operate/services/protocol.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/operate/services/protocol.py b/operate/services/protocol.py index 709e65576..4c97a51c9 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -23,6 +23,7 @@ import contextlib import io import json +import logging import tempfile import time import typing as t @@ -599,6 +600,7 @@ def swap( # pylint: disable=too-many-arguments,too-many-locals self, service_id: int, multisig: str, owner_key: str, new_owner_address: str ) -> None: """Swap safe owner.""" + logging.info(f"Swapping safe for service {service_id} [{multisig}]...") self._patch() manager = ServiceManager( service_id=service_id, @@ -708,9 +710,6 @@ def staking_rewards_available(self, staking_contract: str) -> bool: ) return available_rewards > 0 - # def get_agent_bond(self, staking_contract: str) -> int: - # self._patch() - class OnChainManager(_ChainUtil): """On chain service management.""" From e6d7af9d74638fe6c2e043bdbf1ed4424c7908be Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 28 Aug 2024 16:42:01 +0100 Subject: [PATCH 38/46] refactor: remove reassignment --- .../MainPage/sections/AddFundsSection.tsx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index d61970e7f..ad3e17053 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -18,7 +18,6 @@ import styled from 'styled-components'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { COW_SWAP_GNOSIS_XDAI_OLAS_URL } from '@/constants/urls'; import { useWallet } from '@/hooks/useWallet'; -import { Address } from '@/types/Address'; import { copyToClipboard } from '@/utils/copyToClipboard'; import { truncateAddress } from '@/utils/truncate'; @@ -66,27 +65,25 @@ export const AddFundsSection = () => { export const OpenAddFundsSection = () => { const { masterSafeAddress } = useWallet(); - const fundingAddress: Address | undefined = masterSafeAddress; - const truncatedFundingAddress: string | undefined = useMemo( - () => fundingAddress && truncateAddress(fundingAddress), - [fundingAddress], + () => masterSafeAddress && truncateAddress(masterSafeAddress), + [masterSafeAddress], ); const handleCopyAddress = useCallback( () => - fundingAddress && - copyToClipboard(fundingAddress).then(() => + masterSafeAddress && + copyToClipboard(masterSafeAddress).then(() => message.success('Copied successfully!'), ), - [fundingAddress], + [masterSafeAddress], ); return ( <> From b3d4356c812f5c92e29c2425e03f0b013798b805 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 28 Aug 2024 16:42:36 +0100 Subject: [PATCH 39/46] refactor: remove fragment --- .../StakingContractSection/index.tsx | 66 +++++++++---------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 0c8f3ccf0..856a5648f 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -287,40 +287,38 @@ export const StakingContractSection = ({ {cantMigrateAlert} {/* Switch to program button */} { - <> - - - - + + + } {stakingProgram === StakingProgram.Beta && (