From 10b467fb38ade229d2db3352ec08e4596c66370f Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 5 Nov 2024 13:15:39 +0000 Subject: [PATCH 001/463] chore: import axios --- frontend/package.json | 3 ++- frontend/yarn.lock | 52 ++++++++++++++++++++++++++++++++++++++----- package.json | 4 ++-- yarn.lock | 39 ++++++++++++++++++++++++++------ 4 files changed, 83 insertions(+), 15 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index d5b99af41..cb0ae8066 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,6 +6,7 @@ "@fontsource/inter": "^5.0.17", "@tanstack/react-query": "^5.29.0", "antd": "^5.14.0", + "axios": "^1.7.7", "ethers": "5.7.2", "ethers-multicall": "^0.2.3", "graphql": "^16.8.1", @@ -56,4 +57,4 @@ "start": "next start" }, "version": "0.1.0" -} \ No newline at end of file +} diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 7723c1c38..5f4411fc4 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1993,6 +1993,15 @@ axe-core@=4.7.0: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== +axios@^1.7.7: + version "1.7.7" + resolved "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axobject-query@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" @@ -3230,6 +3239,11 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== +follow-redirects@^1.15.6: + version "1.15.9" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -4937,6 +4951,11 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" @@ -5676,8 +5695,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - name string-width-cjs +"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== @@ -5741,7 +5768,14 @@ string.prototype.trimstart@^1.0.8: define-properties "^1.2.1" es-object-atoms "^1.0.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== @@ -6216,8 +6250,16 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: - name wrap-ansi-cjs +"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== diff --git a/package.json b/package.json index 2d290e65f..41d42f011 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "@tanstack/react-query": "^5.29.0", "adm-zip": "^0.5.12", "antd": "^5.14.0", - "axios": "^1.7.2", + "axios": "^1.7.7", "child_process": "^1.0.2", "cross-env": "^7.0.3", "dotenv": "^16.4.5", @@ -64,4 +64,4 @@ "build:pearl": "sh build_pearl.sh" }, "version": "0.1.0-rc184" -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index b8e7bcff5..192286505 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1570,10 +1570,10 @@ atomically@^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" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621" - integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw== +axios@^1.7.7: + version "1.7.7" + resolved "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" @@ -5086,7 +5086,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== @@ -5111,7 +5120,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== @@ -5491,7 +5507,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 ee7f55bdc9768195cc56b57067875dccf1f5edf9 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 5 Nov 2024 13:15:55 +0000 Subject: [PATCH 002/463] refactor: rename middleware enums --- frontend/client/enums.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index f880c942d..9fced3f3d 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -1,4 +1,4 @@ -export enum Action { +export enum MiddlewareAction { STATUS = 0, BUILD = 1, DEPLOY = 2, @@ -15,12 +15,12 @@ export enum MiddlewareChain { MODE = 6, } -export enum Ledger { +export enum MiddlewareLedger { ETHEREUM = 0, SOLANA = 1, } -export enum DeploymentStatus { +export enum MiddlewareDeploymentStatus { CREATED = 0, BUILT = 1, DEPLOYING = 2, @@ -30,7 +30,7 @@ export enum DeploymentStatus { DELETED = 6, } -export enum AccountIsSetup { +export enum MiddlewareAccountIsSetup { True, False, Loading, From 80a86f9465a53b2809cafbc71ac062c1ca1202a9 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 5 Nov 2024 13:16:10 +0000 Subject: [PATCH 003/463] chore: enum refactored imports --- frontend/client/types.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 805909cbd..e461348d3 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -1,13 +1,17 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; -import { DeploymentStatus, Ledger, MiddlewareChain } from './enums'; +import { + MiddlewareChain, + MiddlewareDeploymentStatus, + MiddlewareLedger, +} from './enums'; export type ServiceHash = string; export type LedgerConfig = { rpc: string; - type: Ledger; + type: MiddlewareLedger; chain: MiddlewareChain; }; @@ -36,7 +40,7 @@ export type ChainData = { }; }; -export type Service = { +export type MiddlewareServiceResponse = { name: string; hash: string; keys: ServiceKeys[]; @@ -84,7 +88,7 @@ export type DeployedNodes = { }; export type Deployment = { - status: DeploymentStatus; + status: MiddlewareDeploymentStatus; nodes: DeployedNodes; }; @@ -128,7 +132,7 @@ export type AppInfo = { export type WalletResponse = { address: Address; safe_chains: MiddlewareChain[]; - ledger_type: Ledger; + ledger_type: MiddlewareLedger; safes: { [middlewareChainId in (typeof MiddlewareChain)[keyof typeof MiddlewareChain]]: Address; }; From 22321c67a00958561bf5ec7999f0b81ca80dc039 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 5 Nov 2024 13:17:30 +0000 Subject: [PATCH 004/463] chore: enum refactored imports --- .../MainPage/header/AgentButton.tsx | 32 +++++++------- .../components/MainPage/header/AgentHead.tsx | 8 ++-- frontend/components/MainPage/header/index.tsx | 8 ++-- .../sections/KeepAgentRunningSection.tsx | 4 +- .../StakingContractSection/MigrateButton.tsx | 4 +- .../StakingContractSection/useMigrate.tsx | 8 ++-- .../components/SetupPage/SetupWelcome.tsx | 22 +++++----- .../context/SystemNotificationTriggers.tsx | 4 +- frontend/hooks/useServices.ts | 42 +++++++++++-------- frontend/service/Services.ts | 15 +++++-- 10 files changed, 80 insertions(+), 67 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index 74886dfcf..85f9b3e8c 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -2,7 +2,7 @@ import { InfoCircleOutlined } from '@ant-design/icons'; import { Button, ButtonProps, Flex, Popover, Tooltip, Typography } from 'antd'; import { useCallback, useMemo } from 'react'; -import { DeploymentStatus, MiddlewareChain } from '@/client'; +import { MiddlewareChain, MiddlewareDeploymentStatus } from '@/client'; import { COLOR } from '@/constants/colors'; import { DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; @@ -85,7 +85,7 @@ const AgentRunningButton = () => { setIsServicePollingPaused(true); // Optimistically update service status - setServiceStatus(DeploymentStatus.STOPPING); + setServiceStatus(MiddlewareDeploymentStatus.STOPPING); try { await ServicesService.stopDeployment(service.hash); } catch (error) { @@ -178,7 +178,7 @@ const AgentNotRunningButton = () => { setIsStakingContractInfoPollingPaused(true); // Mock "DEPLOYING" status (service polling will update this once resumed) - setServiceStatus(DeploymentStatus.DEPLOYING); + setServiceStatus(MiddlewareDeploymentStatus.DEPLOYING); // Get the active staking program id; default id if there's no agent yet const stakingProgramId: StakingProgramId = @@ -227,7 +227,7 @@ const AgentNotRunningButton = () => { } // Can assume successful deployment - setServiceStatus(DeploymentStatus.DEPLOYED); + setServiceStatus(MiddlewareDeploymentStatus.DEPLOYED); // TODO: remove this workaround, middleware should respond when agent is staked & confirmed running after `createService` call await delayInSeconds(5); @@ -265,15 +265,15 @@ const AgentNotRunningButton = () => { // if the agent is NOT running and the balance is too low, // user should not be able to start the agent const isServiceInactive = - serviceStatus === DeploymentStatus.BUILT || - serviceStatus === DeploymentStatus.STOPPED; + serviceStatus === MiddlewareDeploymentStatus.BUILT || + serviceStatus === MiddlewareDeploymentStatus.STOPPED; if (isServiceInactive && isLowBalance) { return false; } - if (serviceStatus === DeploymentStatus.DEPLOYED) return false; - if (serviceStatus === DeploymentStatus.DEPLOYING) return false; - if (serviceStatus === DeploymentStatus.STOPPING) return false; + if (serviceStatus === MiddlewareDeploymentStatus.DEPLOYED) return false; + if (serviceStatus === MiddlewareDeploymentStatus.DEPLOYING) return false; + if (serviceStatus === MiddlewareDeploymentStatus.STOPPING) return false; if (!requiredOlas) return false; @@ -324,15 +324,15 @@ export const AgentButton = () => { return ); - }, [ - goto, - isActiveStakingProgramLoaded, - stakingContractName, - canUpdateStakingContract, - ]); + }, [goto, isActiveStakingProgramLoaded, stakingContractName]); return ( @@ -60,18 +54,7 @@ export const StakingContractUpdate = ({ > Staking contract - {canUpdateStakingContract ? ( - stakingButton - ) : ( - Fund your agent to manage staking contracts} - > - {stakingButton} - - )} + {stakingButton} ); From 65fc297eaf99abf9210c4d23fa27d921d99b5b4d Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 11:09:47 +0000 Subject: [PATCH 018/463] refactor: remove stakingProgramId prop from StakingContractUpdate component for simplification --- .../MainPage/sections/StakingContractUpdate.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/frontend/components/MainPage/sections/StakingContractUpdate.tsx b/frontend/components/MainPage/sections/StakingContractUpdate.tsx index ae667b2cc..e8ad184c1 100644 --- a/frontend/components/MainPage/sections/StakingContractUpdate.tsx +++ b/frontend/components/MainPage/sections/StakingContractUpdate.tsx @@ -4,26 +4,20 @@ import { useMemo } from 'react'; import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { Pages } from '@/enums/PageState'; -import { StakingProgramId } from '@/enums/StakingProgram'; import { usePageState } from '@/hooks/usePageState'; import { useStakingProgram } from '@/hooks/useStakingProgram'; -import { useMigrate } from '../../ManageStakingPage/StakingContractSection/useMigrate'; import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; -type StakingContractUpdateProps = { stakingProgramId: StakingProgramId }; -export const StakingContractUpdate = ({ - stakingProgramId, -}: StakingContractUpdateProps) => { +export const StakingContractUpdate = () => { const { goto } = usePageState(); const { activeStakingProgramMeta, isActiveStakingProgramLoaded, defaultStakingProgramId, } = useStakingProgram(); - const { canUpdateStakingContract } = useMigrate(stakingProgramId); const stakingContractName = useMemo(() => { if (activeStakingProgramMeta) return activeStakingProgramMeta.name; From d2d9f5cae90cc7644e238d67dcf99bb71a1f16a6 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 11:10:09 +0000 Subject: [PATCH 019/463] refactor: remove defaultStakingProgramId usage in Main component for clarity --- frontend/components/MainPage/index.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index a6fe872f0..5c52b57ca 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -26,8 +26,7 @@ export const Main = () => { const { backupSafeAddress } = useMasterSafe(); const { updateServicesState } = useServices(); const { updateBalances, isLoaded, setIsLoaded } = useBalance(); - const { activeStakingProgramId, defaultStakingProgramId } = - useStakingProgram(); + const { activeStakingProgramId } = useStakingProgram(); const { hasEnoughServiceSlots } = useStakingContractInfo(); useEffect(() => { @@ -75,9 +74,7 @@ export const Main = () => { - + From c4598d894ca1abb27e45ef531add0feb151f4fa7 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 13:24:00 +0000 Subject: [PATCH 020/463] refactor: update staking program status enum and related logic for clarity --- .../MainPage/header/AgentButton.tsx | 50 +++++--- .../header/CannotStartAgentPopover.tsx | 25 +++- frontend/components/MainPage/index.tsx | 41 +++++-- .../NoAvailableSlotsOnTheContract.tsx | 40 +++++-- .../sections/StakingContractUpdate.tsx | 29 ++++- .../CantMigrateAlert.tsx | 9 +- .../StakingContractSection/MigrateButton.tsx | 24 ++-- .../StakingContractDetails.tsx | 34 +++--- .../StakingContractTag.tsx | 5 +- .../StakingContractSection/index.tsx | 26 +++-- .../StakingContractSection/useMigrate.tsx | 108 +++++++++++++----- .../context/StakingContractInfoProvider.tsx | 21 ++-- frontend/context/StakingProgramProvider.tsx | 13 ++- frontend/enums/StakingProgramStatus.ts | 3 +- frontend/hooks/useStakingContractInfo.ts | 35 +++--- frontend/hooks/useStakingProgram.ts | 2 + frontend/utils/service.ts | 4 +- 17 files changed, 331 insertions(+), 138 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index eb24147ed..af3d10988 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -10,7 +10,10 @@ import { useElectronApi } from '@/hooks/useElectronApi'; import { useReward } from '@/hooks/useReward'; import { useServices } from '@/hooks/useServices'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; -import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; +import { + useStakingContractContext, + useStakingContractInfo, +} from '@/hooks/useStakingContractInfo'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { useStore } from '@/hooks/useStore'; import { useWallet } from '@/hooks/useWallet'; @@ -140,16 +143,23 @@ const AgentNotRunningButton = () => { updateBalances, } = useBalance(); const { storeState } = useStore(); + const { - isEligibleForStaking, - isAgentEvicted, + isStakingContractInfoLoaded, setIsPaused: setIsStakingContractInfoPollingPaused, updateActiveStakingContractInfo, - hasEnoughServiceSlots, - } = useStakingContractInfo(); + } = useStakingContractContext(); + const { activeStakingProgramId, defaultStakingProgramId } = useStakingProgram(); + const { + isEligibleForStaking, + isAgentEvicted, + hasEnoughServiceSlots, + isServiceStaked, + } = useStakingContractInfo(activeStakingProgramId ?? defaultStakingProgramId); + // const minStakingDeposit = // stakingContractInfoRecord?.[activeStakingProgram ?? defaultStakingProgram] // ?.minStakingDeposit; @@ -266,6 +276,8 @@ const AgentNotRunningButton = () => { ]); const isDeployable = useMemo(() => { + if (!isStakingContractInfoLoaded) return false; + // if the agent is NOT running and the balance is too low, // user should not be able to start the agent const isServiceInactive = @@ -282,7 +294,7 @@ const AgentNotRunningButton = () => { if (!requiredOlas) return false; // If no slots available, agent cannot be started - if (!hasEnoughServiceSlots) return false; + if (!hasEnoughServiceSlots && !isServiceStaked) return false; // case where service exists & user has initial funded if (service && storeState?.isInitialFunded) { @@ -299,16 +311,18 @@ const AgentNotRunningButton = () => { return hasEnoughOlas && hasEnoughEth; }, [ + isStakingContractInfoLoaded, serviceStatus, + isLowBalance, + requiredOlas, + hasEnoughServiceSlots, + isServiceStaked, service, storeState?.isInitialFunded, isEligibleForStaking, isAgentEvicted, safeOlasBalanceWithStaked, - requiredOlas, totalEthBalance, - isLowBalance, - hasEnoughServiceSlots, ]); const buttonProps: ButtonProps = { @@ -324,11 +338,20 @@ const AgentNotRunningButton = () => { }; export const AgentButton = () => { - const { service, serviceStatus, hasInitialLoaded } = useServices(); - const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo(); + const { + service, + serviceStatus, + hasInitialLoaded: isServicesLoaded, + } = useServices(); + const { activeStakingProgramId, defaultStakingProgramId } = + useStakingProgram(); + const { isStakingContractInfoLoaded } = useStakingContractContext(); + const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo( + activeStakingProgramId ?? defaultStakingProgramId, + ); return useMemo(() => { - if (!hasInitialLoaded) { + if (!isServicesLoaded || !isStakingContractInfoLoaded) { return ); - }, [goto, isActiveStakingProgramLoaded, stakingContractName]); + }, [ + goto, + isActiveStakingProgramLoaded, + isStakingContractInfoLoaded, + serviceIsTransitioning, + stakingContractName, + ]); return ( @@ -47,8 +67,7 @@ export const StakingContractUpdate = () => { style={{ width: '100%' }} > Staking contract - - {stakingButton} + {gotoManageStakingButton} ); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx index adfa9c0fe..d75f6a6aa 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx @@ -5,7 +5,10 @@ import { CustomAlert } from '@/components/Alert'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; -import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; +import { + useStakingContractContext, + useStakingContractInfo, +} from '@/hooks/useStakingContractInfo'; import { getMinimumStakedAmountRequired } from '@/utils/service'; import { CantMigrateReason } from './useMigrate'; @@ -18,7 +21,8 @@ const AlertInsufficientMigrationFunds = ({ stakingProgramId, }: CantMigrateAlertProps) => { const { serviceTemplate } = useServiceTemplates(); - const { isServiceStaked } = useStakingContractInfo(); + const { isStakingContractInfoLoaded } = useStakingContractContext(); + const { isServiceStaked } = useStakingContractInfo(stakingProgramId); const { masterSafeBalance: safeBalance, totalOlasStakedBalance } = useBalance(); @@ -27,6 +31,7 @@ const AlertInsufficientMigrationFunds = ({ stakingProgramId, ); + if (!isStakingContractInfoLoaded) return null; if (isNil(totalOlasRequiredForStaking)) return null; if (isNil(safeBalance?.OLAS)) return null; if (isNil(totalOlasStakedBalance)) return null; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index 2f4f7e468..7c0f71067 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -30,10 +30,18 @@ export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { hasInitialLoaded: isServicesLoaded, service, } = useServices(); + + const { + activeStakingProgramId, + defaultStakingProgramId, + setDefaultStakingProgramId, + } = useStakingProgram(); const { setIsPaused: setIsBalancePollingPaused } = useBalance(); - const { updateActiveStakingProgramId: updateStakingProgram } = - useStakingProgram(); - const { activeStakingContractInfo } = useStakingContractInfo(); + const { updateActiveStakingProgramId } = useStakingProgram(); + + const { stakingContractInfo: currentStakingContractInfo } = + useStakingContractInfo(activeStakingProgramId ?? defaultStakingProgramId); + const { setMigrationModalOpen } = useModals(); const { migrateValidation, firstDeployValidation } = @@ -43,7 +51,6 @@ export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { const isFirstDeploy = useMemo(() => { if (!isServicesLoaded) return false; if (service) return false; - return true; }, [isServicesLoaded, service]); @@ -54,17 +61,17 @@ export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { if ( validation.reason === CantMigrateReason.NotStakedForMinimumDuration && - !isNil(activeStakingContractInfo) + !isNil(currentStakingContractInfo) ) { return ( ); } return validation.reason; - }, [activeStakingContractInfo, validation]); + }, [currentStakingContractInfo, validation]); return ( @@ -75,6 +82,7 @@ export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { onClick={async () => { setIsServicePollingPaused(true); setIsBalancePollingPaused(true); + setDefaultStakingProgramId(stakingProgramId); try { setServiceStatus(DeploymentStatus.DEPLOYING); @@ -88,7 +96,7 @@ export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { stakingProgramId === StakingProgramId.BetaMechMarketplace, }); - await updateStakingProgram(); + await updateActiveStakingProgramId(); setMigrationModalOpen(true); } catch (error) { diff --git a/frontend/components/ManageStakingPage/StakingContractSection/StakingContractDetails.tsx b/frontend/components/ManageStakingPage/StakingContractSection/StakingContractDetails.tsx index 607807cf1..2d4f9ff9b 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/StakingContractDetails.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/StakingContractDetails.tsx @@ -2,27 +2,29 @@ import { Alert, Skeleton } from 'antd'; import { useMemo } from 'react'; import { InfoBreakdownList } from '@/components/InfoBreakdown'; -import { NA } from '@/constants/symbols'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; +import { useStakingContractContext } from '@/hooks/useStakingContractInfo'; export const StakingContractDetails = ({ stakingProgramId, }: { stakingProgramId: StakingProgramId; }) => { - const { stakingContractInfoRecord } = useStakingContractInfo(); + const { stakingContractInfoRecord, isStakingContractInfoLoaded } = + useStakingContractContext(); - const balances = useMemo(() => { - if (!stakingContractInfoRecord) return null; - if (!stakingProgramId) return null; - if (!stakingContractInfoRecord?.[stakingProgramId]) return null; + const list = useMemo(() => { + if (!isStakingContractInfoLoaded) return; + if (!stakingContractInfoRecord) return; + if (!stakingProgramId) return; + if (!stakingContractInfoRecord?.[stakingProgramId]) return; const details = stakingContractInfoRecord[stakingProgramId]; + return [ { left: 'Available slots', - right: details.maxNumServices || NA, + right: `${details.maxNumServices! - details.serviceIds!.length} / ${details.maxNumServices}`, }, { left: 'Rewards per epoch', @@ -38,13 +40,17 @@ export const StakingContractDetails = ({ right: `${details.olasStakeRequired} OLAS`, }, ]; - }, [stakingContractInfoRecord, stakingProgramId]); + }, [ + isStakingContractInfoLoaded, + stakingContractInfoRecord, + stakingProgramId, + ]); - if (!stakingContractInfoRecord) { + if (!isStakingContractInfoLoaded) { return ; } - if (!balances) { + if (!stakingContractInfoRecord) { return ( + ); }; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/StakingContractTag.tsx b/frontend/components/ManageStakingPage/StakingContractSection/StakingContractTag.tsx index cd9e525df..316f3a606 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/StakingContractTag.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/StakingContractTag.tsx @@ -7,8 +7,11 @@ export const StakingContractTag = ({ }: { status: StakingProgramStatus | null; }) => { - if (status === StakingProgramStatus.Selected) { + if (status === StakingProgramStatus.Active) { return Active; } + if (status === StakingProgramStatus.Default) { + return Default; + } return null; }; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index d7759ff16..ce45bdc7d 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -38,29 +38,31 @@ export const StakingContractSection = ({ const stakingProgramMeta = STAKING_PROGRAM_META[stakingProgramId]; - /** - * Returns `true` if this stakingProgram is active, - * or user is unstaked and this is the default - */ - const isActiveStakingProgram = useMemo(() => { - if (activeStakingProgramId === null) - return defaultStakingProgramId === stakingProgramId; - return activeStakingProgramId === stakingProgramId; - }, [activeStakingProgramId, defaultStakingProgramId, stakingProgramId]); + // /** + // * Returns `true` if this stakingProgram is active, + // * or user is unstaked and this is the default + // */ + // const isActiveStakingProgram = useMemo(() => { + // if (activeStakingProgramId === null) + // return defaultStakingProgramId === stakingProgramId; + // return activeStakingProgramId === stakingProgramId; + // }, [activeStakingProgramId, defaultStakingProgramId, stakingProgramId]); const contractTagStatus = useMemo(() => { if (activeStakingProgramId === stakingProgramId) - return StakingProgramStatus.Selected; + return StakingProgramStatus.Active; // Pearl is not staked, set as Selected if default if (!activeStakingProgramId && stakingProgramId === defaultStakingProgramId) - return StakingProgramStatus.Selected; + return StakingProgramStatus.Default; // Otherwise, no tag return null; }, [activeStakingProgramId, defaultStakingProgramId, stakingProgramId]); - const showMigrateButton = !isActiveStakingProgram; + const showMigrateButton = + stakingProgramId !== (activeStakingProgramId ?? defaultStakingProgramId); + const showFundingButton = useMemo(() => { if (migrateValidation.canMigrate) return false; return ( diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index ef67412ed..736df82e7 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -7,7 +7,10 @@ import { useBalance } from '@/hooks/useBalance'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; import { useServices } from '@/hooks/useServices'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; -import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; +import { + useStakingContractContext, + useStakingContractInfo, +} from '@/hooks/useStakingContractInfo'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { getMinimumStakedAmountRequired } from '@/utils/service'; @@ -47,16 +50,15 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { useStakingProgram(); const { needsInitialFunding } = useNeedsFunds(); + const { stakingContractInfoRecord, isStakingContractInfoLoaded } = + useStakingContractContext(); + const { - activeStakingContractInfo, + stakingContractInfo, isServiceStaked, isServiceStakedForMinimumDuration, - isStakingContractInfoLoaded, - stakingContractInfoRecord, hasEnoughServiceSlots, - } = useStakingContractInfo(); - - const stakingContractInfo = stakingContractInfoRecord?.[stakingProgramId]; + } = useStakingContractInfo(stakingProgramId); const { hasInitialLoaded: isServicesLoaded } = useServices(); @@ -94,11 +96,25 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { return { canMigrate: false, reason: CantMigrateReason.LoadingServices }; } + // Services must be not be running or in a transitional state + if ( + [ + DeploymentStatus.DEPLOYED, + DeploymentStatus.DEPLOYING, + DeploymentStatus.STOPPING, + ].some((status) => status === serviceStatus) + ) { + return { + canMigrate: false, + reason: CantMigrateReason.PearlCurrentlyRunning, + }; + } + if (!isBalanceLoaded) { return { canMigrate: false, reason: CantMigrateReason.LoadingBalance }; } - if (isServicesLoaded && !isStakingContractInfoLoaded) { + if (!isStakingContractInfoLoaded) { return { canMigrate: false, reason: CantMigrateReason.LoadingStakingContractInfo, @@ -120,6 +136,16 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { }; } + if ( + (stakingContractInfo.serviceIds ?? [])?.length >= + (stakingContractInfo.maxNumServices ?? 0) + ) { + return { + canMigrate: false, + reason: CantMigrateReason.NoAvailableStakingSlots, + }; + } + if ((stakingContractInfo.availableRewards ?? 0) <= 0) { return { canMigrate: false, @@ -144,20 +170,6 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { }; } - // Services must be not be running or in a transitional state - if ( - [ - DeploymentStatus.DEPLOYED, - DeploymentStatus.DEPLOYING, - DeploymentStatus.STOPPING, - ].some((status) => status === serviceStatus) - ) { - return { - canMigrate: false, - reason: CantMigrateReason.PearlCurrentlyRunning, - }; - } - if (activeStakingProgramId === null && !isServiceStaked) { return { canMigrate: true }; } @@ -171,7 +183,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { }; } - if (activeStakingContractInfo && !isServiceStakedForMinimumDuration) { + if (stakingContractInfo && !isServiceStakedForMinimumDuration) { return { canMigrate: false, reason: CantMigrateReason.NotStakedForMinimumDuration, @@ -189,7 +201,6 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { hasEnoughOlasToMigrate, isServiceStaked, activeStakingProgramMeta?.canMigrateTo, - activeStakingContractInfo, isServiceStakedForMinimumDuration, serviceStatus, ]); @@ -199,19 +210,52 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { return { canMigrate: false, reason: CantMigrateReason.LoadingServices }; } + // Services must be not be running or in a transitional state + if ( + [ + DeploymentStatus.DEPLOYED, + DeploymentStatus.DEPLOYING, + DeploymentStatus.STOPPING, + ].some((status) => status === serviceStatus) + ) { + return { + canMigrate: false, + reason: CantMigrateReason.PearlCurrentlyRunning, + }; + } + if (!isBalanceLoaded) { return { canMigrate: false, reason: CantMigrateReason.LoadingBalance }; } - if (!hasEnoughOlasForFirstRun) { + // staking contract requirements + + if (!isStakingContractInfoLoaded) { return { canMigrate: false, - reason: CantMigrateReason.InsufficientOlasToMigrate, + reason: CantMigrateReason.LoadingStakingContractInfo, }; } const stakingContractInfo = stakingContractInfoRecord?.[stakingProgramId]; + if (!stakingContractInfo) { + return { + canMigrate: false, + reason: CantMigrateReason.CannotFindStakingContractInfo, + }; + } + + if ( + (stakingContractInfo.serviceIds ?? [])?.length >= + (stakingContractInfo.maxNumServices ?? 0) + ) { + return { + canMigrate: false, + reason: CantMigrateReason.NoAvailableStakingSlots, + }; + } + if ((stakingContractInfo?.availableRewards ?? 0) <= 0) { return { canMigrate: false, @@ -226,13 +270,23 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { }; } + // fund requirements + + if (!hasEnoughOlasForFirstRun) { + return { + canMigrate: false, + reason: CantMigrateReason.InsufficientOlasToMigrate, + }; + } + return { canMigrate: true }; }, [ isServicesLoaded, isBalanceLoaded, - hasEnoughOlasForFirstRun, + isStakingContractInfoLoaded, stakingContractInfoRecord, stakingProgramId, + hasEnoughOlasForFirstRun, ]); const canUpdateStakingContract = useMemo(() => { diff --git a/frontend/context/StakingContractInfoProvider.tsx b/frontend/context/StakingContractInfoProvider.tsx index 8533046d4..504ed66b1 100644 --- a/frontend/context/StakingContractInfoProvider.tsx +++ b/frontend/context/StakingContractInfoProvider.tsx @@ -74,14 +74,6 @@ export const StakingContractInfoProvider = ({ ).then(setActiveStakingContractInfo); }, [activeStakingProgramId, serviceId]); - useInterval( - async () => { - await updateStakingContractInfoRecord().catch(console.error); - await updateActiveStakingContractInfo().catch(console.error); - }, - isPaused ? null : FIVE_SECONDS_INTERVAL, - ); - /** Updates general staking contract information, not user or service specific */ const updateStakingContractInfoRecord = async () => { const stakingPrograms = Object.values(StakingProgramId); @@ -108,15 +100,22 @@ export const StakingContractInfoProvider = ({ setStakingContractInfoRecord(stakingContractInfoRecord); setIsStakingContractInfoLoaded(true); } catch (e) { - console.error(e); + console.error({ e }); } }; useEffect(() => { - // Load generic staking contract info record on mount - updateStakingContractInfoRecord(); + updateStakingContractInfoRecord().catch(console.error); }, []); + useInterval( + async () => { + await updateStakingContractInfoRecord().catch(console.error); + await updateActiveStakingContractInfo().catch(console.error); + }, + isPaused ? null : FIVE_SECONDS_INTERVAL, + ); + return ( Promise; + setDefaultStakingProgramId: (stakingProgramId: StakingProgramId) => void; }>({ activeStakingProgramId: undefined, - defaultStakingProgramId: DEFAULT_STAKING_PROGRAM_ID, + defaultStakingProgramId: INITIAL_DEFAULT_STAKING_PROGRAM_ID, updateActiveStakingProgramId: async () => {}, + setDefaultStakingProgramId: () => {}, }); /** Determines the current active staking program, if any */ @@ -25,6 +27,10 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { const [activeStakingProgramId, setActiveStakingProgramId] = useState(); + const [defaultStakingProgramId, setDefaultStakingProgramId] = useState( + INITIAL_DEFAULT_STAKING_PROGRAM_ID, + ); + const updateActiveStakingProgramId = useCallback(async () => { // if no service nft, not staked const serviceId = @@ -52,7 +58,8 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { value={{ activeStakingProgramId, updateActiveStakingProgramId, - defaultStakingProgramId: DEFAULT_STAKING_PROGRAM_ID, + defaultStakingProgramId, + setDefaultStakingProgramId, }} > {children} diff --git a/frontend/enums/StakingProgramStatus.ts b/frontend/enums/StakingProgramStatus.ts index d161434b7..7e7364d09 100644 --- a/frontend/enums/StakingProgramStatus.ts +++ b/frontend/enums/StakingProgramStatus.ts @@ -1,3 +1,4 @@ export enum StakingProgramStatus { - Selected = 'current', + Active = 'current', + Default = 'default', } diff --git a/frontend/hooks/useStakingContractInfo.ts b/frontend/hooks/useStakingContractInfo.ts index 96860360d..e8de2168c 100644 --- a/frontend/hooks/useStakingContractInfo.ts +++ b/frontend/hooks/useStakingContractInfo.ts @@ -2,10 +2,9 @@ import { isNil } from 'lodash'; import { useContext } from 'react'; import { StakingContractInfoContext } from '@/context/StakingContractInfoProvider'; +import { StakingProgramId } from '@/enums/StakingProgram'; -import { useServices } from './useServices'; - -export const useStakingContractInfo = () => { +export const useStakingContractContext = () => { const { activeStakingContractInfo, isPaused, @@ -14,17 +13,20 @@ export const useStakingContractInfo = () => { updateActiveStakingContractInfo, setIsPaused, } = useContext(StakingContractInfoContext); + return { + activeStakingContractInfo, + isPaused, + isStakingContractInfoLoaded, + stakingContractInfoRecord, + updateActiveStakingContractInfo, + setIsPaused, + }; +}; - const { service } = useServices(); +export const useStakingContractInfo = (stakingProgramId: StakingProgramId) => { + const { stakingContractInfoRecord } = useStakingContractContext(); - // TODO: find a better way to handle this, currently stops react lifecycle hooks being implemented below it - if (!service || !activeStakingContractInfo) - return { - stakingContractInfoRecord, - updateActiveStakingContractInfo, - setIsPaused, - isPaused, - }; + const stakingContractInfo = stakingContractInfoRecord?.[stakingProgramId]; const { serviceStakingState, @@ -33,7 +35,7 @@ export const useStakingContractInfo = () => { maxNumServices, minimumStakingDuration, availableRewards, - } = activeStakingContractInfo; + } = stakingContractInfo ?? {}; const isRewardsAvailable = availableRewards ?? 0 > 0; @@ -81,18 +83,13 @@ export const useStakingContractInfo = () => { (serviceStakingStartTime ?? 0) + (minimumStakingDuration ?? 0); return { - activeStakingContractInfo, hasEnoughServiceSlots, isAgentEvicted, evictionExpiresAt, isEligibleForStaking, - isPaused, isRewardsAvailable, isServiceStakedForMinimumDuration, isServiceStaked, - isStakingContractInfoLoaded, - stakingContractInfoRecord, - updateActiveStakingContractInfo, - setIsPaused, + stakingContractInfo, }; }; diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index da4f3e8c9..13dc21686 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -14,6 +14,7 @@ export const useStakingProgram = () => { activeStakingProgramId, defaultStakingProgramId, updateActiveStakingProgramId, + setDefaultStakingProgramId, } = useContext(StakingProgramContext); const isActiveStakingProgramLoaded = activeStakingProgramId !== undefined; @@ -54,5 +55,6 @@ export const useStakingProgram = () => { defaultStakingProgramMeta, isActiveStakingProgramLoaded, updateActiveStakingProgramId, + setDefaultStakingProgramId, }; }; diff --git a/frontend/utils/service.ts b/frontend/utils/service.ts index 53ec7fc7c..3b3fe45b4 100644 --- a/frontend/utils/service.ts +++ b/frontend/utils/service.ts @@ -1,11 +1,11 @@ import { ServiceTemplate } from '@/client'; -import { DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider'; +import { INITIAL_DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; /** TODO: update from hardcoded, workaround for quick release */ export const getMinimumStakedAmountRequired = ( serviceTemplate?: ServiceTemplate, //TODO: remove, as unused - stakingProgramId: StakingProgramId = DEFAULT_STAKING_PROGRAM_ID, + stakingProgramId: StakingProgramId = INITIAL_DEFAULT_STAKING_PROGRAM_ID, ): number | undefined => { if (stakingProgramId === StakingProgramId.Alpha) { return 20; From 15be025e1a1fb67507aa6f283eac9c3e87c3d5ff Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 14:18:16 +0000 Subject: [PATCH 021/463] fix: backup wallet alert wait for owners to be loaded --- .../MainPage/sections/AlertSections/AddBackupWalletAlert.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx index 239521382..7ee41c49e 100644 --- a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx +++ b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx @@ -1,4 +1,5 @@ import { Flex, Typography } from 'antd'; +import { isNil } from 'lodash'; import { Pages } from '@/enums/PageState'; import { useMasterSafe } from '@/hooks/useMasterSafe'; @@ -10,8 +11,9 @@ const { Text } = Typography; export const AddBackupWalletAlert = () => { const { goto } = usePageState(); - const { backupSafeAddress } = useMasterSafe(); + const { backupSafeAddress, masterSafeOwners } = useMasterSafe(); + if (isNil(masterSafeOwners)) return null; if (backupSafeAddress) return null; return ( From c8ff7df2b4414c5e0dc4dcd390fa015fe2993886 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 14:18:38 +0000 Subject: [PATCH 022/463] fix: support both xdai and olas gas requirements on first deploy --- .../CantMigrateAlert.tsx | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx index d75f6a6aa..80741fdbd 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx @@ -2,8 +2,10 @@ import { Flex, Typography } from 'antd'; import { isNil } from 'lodash'; import { CustomAlert } from '@/components/Alert'; +import { LOW_MASTER_SAFE_BALANCE } from '@/constants/thresholds'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; +import { useNeedsFunds } from '@/hooks/useNeedsFunds'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useStakingContractContext, @@ -25,6 +27,7 @@ const AlertInsufficientMigrationFunds = ({ const { isServiceStaked } = useStakingContractInfo(stakingProgramId); const { masterSafeBalance: safeBalance, totalOlasStakedBalance } = useBalance(); + const { serviceFundRequirements, isInitialFunded } = useNeedsFunds(); const totalOlasRequiredForStaking = getMinimumStakedAmountRequired( serviceTemplate, @@ -40,18 +43,24 @@ const AlertInsufficientMigrationFunds = ({ ? totalOlasRequiredForStaking - (totalOlasStakedBalance + safeBalance.OLAS) // when staked : totalOlasRequiredForStaking - safeBalance.OLAS; // when not staked + const requiredXdaiDeposit = isInitialFunded + ? LOW_MASTER_SAFE_BALANCE - safeBalance.ETH // is already funded allow minimal maintenance + : serviceFundRequirements.eth - safeBalance.ETH; // otherwise require full initial funding requirements + return ( - - An additional {requiredOlasDeposit} OLAS is required to switch - + Additional funds required - Add {requiredOlasDeposit} OLAS to your account to - meet the contract requirements and switch. +
    + {requiredOlasDeposit > 0 &&
  • {requiredOlasDeposit} OLAS
  • } + {requiredXdaiDeposit > 0 &&
  • {requiredXdaiDeposit} XDAI
  • } +
+ Add the required funds to your account to meet the staking + requirements.
} @@ -107,7 +116,10 @@ export const CantMigrateAlert = ({ return ; } - if (cantMigrateReason === CantMigrateReason.InsufficientOlasToMigrate) { + if ( + cantMigrateReason === CantMigrateReason.InsufficientOlasToMigrate || + cantMigrateReason === CantMigrateReason.InsufficientGasToMigrate + ) { return ( ); From 85f0fc9fcc964250b867523e2875cb45dc85748b Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 14:18:55 +0000 Subject: [PATCH 023/463] fix: support both gas and olas checks --- .../ManageStakingPage/StakingContractSection/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index ce45bdc7d..410b934d0 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -66,7 +66,9 @@ export const StakingContractSection = ({ const showFundingButton = useMemo(() => { if (migrateValidation.canMigrate) return false; return ( - migrateValidation.reason === CantMigrateReason.InsufficientOlasToMigrate + migrateValidation.reason === + CantMigrateReason.InsufficientOlasToMigrate || + migrateValidation.reason === CantMigrateReason.InsufficientGasToMigrate ); }, [migrateValidation]); From 63c37ef7591dc59111e9a92507c50b3383d4c300 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 14:19:10 +0000 Subject: [PATCH 024/463] feat: add insufficient gas enum --- .../StakingContractSection/useMigrate.tsx | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index 736df82e7..87e7e8e30 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -19,6 +19,7 @@ export enum CantMigrateReason { LoadingBalance = 'Loading balance...', LoadingStakingContractInfo = 'Loading staking contract information...', InsufficientOlasToMigrate = 'Insufficient OLAS to switch', + InsufficientGasToMigrate = 'Insufficient XDAI to switch', // TODO: make chain agnostic MigrationNotSupported = 'Switching to this program is not currently supported', NoAvailableRewards = 'This program has no rewards available', NoAvailableStakingSlots = 'The program has no more available slots', @@ -62,6 +63,8 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { const { hasInitialLoaded: isServicesLoaded } = useServices(); + const { hasEnoughEthForInitialFunding } = useNeedsFunds(); + const minimumOlasRequiredToMigrate = useMemo( () => getMinimumStakedAmountRequired(serviceTemplate, stakingProgramId), [serviceTemplate, stakingProgramId], @@ -206,6 +209,10 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { ]); const firstDeployValidation = useMemo(() => { + /** + * @todo fix temporary check for xDai balance on first deploy (same as initial funding requirement) + */ + if (!isServicesLoaded) { return { canMigrate: false, reason: CantMigrateReason.LoadingServices }; } @@ -270,8 +277,6 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { }; } - // fund requirements - if (!hasEnoughOlasForFirstRun) { return { canMigrate: false, @@ -279,14 +284,23 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { }; } + if (!hasEnoughEthForInitialFunding) { + return { + canMigrate: false, + reason: CantMigrateReason.InsufficientGasToMigrate, + }; + } + return { canMigrate: true }; }, [ isServicesLoaded, isBalanceLoaded, + hasEnoughEthForInitialFunding, isStakingContractInfoLoaded, stakingContractInfoRecord, stakingProgramId, hasEnoughOlasForFirstRun, + serviceStatus, ]); const canUpdateStakingContract = useMemo(() => { From 77459c39b1b16016b0b20134f8cb43b3940540bc Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 14:19:35 +0000 Subject: [PATCH 025/463] chore: move isInitialFunded higher --- frontend/hooks/useNeedsFunds.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/hooks/useNeedsFunds.ts b/frontend/hooks/useNeedsFunds.ts index 78117fdaa..76886062f 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -17,6 +17,8 @@ export const useNeedsFunds = () => { ); const { storeState } = useStore(); + const isInitialFunded = storeState?.isInitialFunded; + const { isBalanceLoaded, masterSafeBalance: safeBalance, @@ -51,7 +53,6 @@ export const useNeedsFunds = () => { serviceFundRequirements?.olas, ]); - const isInitialFunded = storeState?.isInitialFunded; const needsInitialFunding: boolean = useMemo(() => { if (isInitialFunded) return false; if (!isBalanceLoaded) return false; From 37988d9aaf96632f7215519861ae8141eea21971 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 14:30:48 +0000 Subject: [PATCH 026/463] bump: rc187 --- package.json | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b9dbb657a..205bf10e5 100644 --- a/package.json +++ b/package.json @@ -63,5 +63,5 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc186" + "version": "0.1.0-rc187" } \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index f5109942f..e5f356ee2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc186" +version = "0.1.0-rc187" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From d1d23a3a1e1bc39aa8d7a775753b67ccd02c04c7 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 15:16:17 +0000 Subject: [PATCH 027/463] fix: fallback to activeStakingProgramInfo if activeStakingProgramId exists --- .../NoAvailableSlotsOnTheContract.tsx | 3 ++- .../context/StakingContractInfoProvider.tsx | 23 ++++++++++++++----- frontend/hooks/useStakingContractInfo.ts | 14 ++++++++--- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx b/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx index 5174f22e5..8975155e2 100644 --- a/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx +++ b/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx @@ -24,7 +24,7 @@ export const NoAvailableSlotsOnTheContract = () => { } = useStakingProgram(); const { isStakingContractInfoLoaded } = useStakingContractContext(); - const { hasEnoughServiceSlots } = useStakingContractInfo( + const { hasEnoughServiceSlots, isServiceStaked } = useStakingContractInfo( activeStakingProgramId ?? defaultStakingProgramId, ); @@ -43,6 +43,7 @@ export const NoAvailableSlotsOnTheContract = () => { if (!isStakingContractInfoLoaded) return null; if (hasEnoughServiceSlots) return null; + if (isServiceStaked) return null; return ( ; + isActiveStakingContractInfoLoaded: boolean; isPaused: boolean; - isStakingContractInfoLoaded: boolean; stakingContractInfoRecord?: Record< StakingProgramId, Partial >; + isStakingContractInfoRecordLoaded: boolean; updateActiveStakingContractInfo: () => Promise; setIsPaused: Dispatch>; }; @@ -36,7 +37,8 @@ export const StakingContractInfoContext = createContext({ activeStakingContractInfo: undefined, isPaused: false, - isStakingContractInfoLoaded: false, + isStakingContractInfoRecordLoaded: false, + isActiveStakingContractInfoLoaded: false, stakingContractInfoRecord: undefined, updateActiveStakingContractInfo: async () => {}, setIsPaused: () => {}, @@ -49,8 +51,14 @@ export const StakingContractInfoProvider = ({ const { activeStakingProgramId } = useContext(StakingProgramContext); const [isPaused, setIsPaused] = useState(false); - const [isStakingContractInfoLoaded, setIsStakingContractInfoLoaded] = - useState(false); + const [ + isStakingContractInfoRecordLoaded, + setIsStakingContractInfoRecordLoaded, + ] = useState(false); + const [ + isActiveStakingContractInfoLoaded, + setIsActiveStakingContractInfoLoaded, + ] = useState(false); const [activeStakingContractInfo, setActiveStakingContractInfo] = useState>(); @@ -72,6 +80,8 @@ export const StakingContractInfoProvider = ({ serviceId, activeStakingProgramId, ).then(setActiveStakingContractInfo); + + setIsActiveStakingContractInfoLoaded(true); }, [activeStakingProgramId, serviceId]); /** Updates general staking contract information, not user or service specific */ @@ -98,7 +108,7 @@ export const StakingContractInfoProvider = ({ ); setStakingContractInfoRecord(stakingContractInfoRecord); - setIsStakingContractInfoLoaded(true); + setIsStakingContractInfoRecordLoaded(true); } catch (e) { console.error({ e }); } @@ -120,7 +130,8 @@ export const StakingContractInfoProvider = ({ { const { activeStakingContractInfo, isPaused, - isStakingContractInfoLoaded, + isStakingContractInfoRecordLoaded: isStakingContractInfoLoaded, stakingContractInfoRecord, updateActiveStakingContractInfo, setIsPaused, @@ -24,9 +26,15 @@ export const useStakingContractContext = () => { }; export const useStakingContractInfo = (stakingProgramId: StakingProgramId) => { - const { stakingContractInfoRecord } = useStakingContractContext(); + const { activeStakingProgramId } = useStakingProgram(); + + const { stakingContractInfoRecord, activeStakingContractInfo } = + useStakingContractContext(); - const stakingContractInfo = stakingContractInfoRecord?.[stakingProgramId]; + const stakingContractInfo = + activeStakingProgramId === stakingProgramId + ? stakingContractInfoRecord?.[stakingProgramId] + : activeStakingContractInfo; const { serviceStakingState, From 40d72aa08311f6994414c8bfa5ee8f71c375e4a0 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 6 Nov 2024 16:10:37 +0000 Subject: [PATCH 028/463] refactor: add useActiveStakingContractInfo, this record is updated seperately with active service id, where as other contract info records are not --- .../MainPage/header/AgentButton.tsx | 32 ++++---- .../header/CannotStartAgentPopover.tsx | 28 +++---- frontend/components/MainPage/index.tsx | 4 +- .../NoAvailableSlotsOnTheContract.tsx | 12 +-- .../sections/StakingContractUpdate.tsx | 6 +- .../CantMigrateAlert.tsx | 8 +- .../CountdownUntilMigration.tsx | 8 +- .../StakingContractSection/MigrateButton.tsx | 31 +++++-- .../StakingContractDetails.tsx | 8 +- .../StakingContractSection/useMigrate.tsx | 23 ++++-- frontend/hooks/useStakingContractInfo.ts | 82 +++++++++++-------- 11 files changed, 135 insertions(+), 107 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index af3d10988..f0846bb6f 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -11,6 +11,7 @@ import { useReward } from '@/hooks/useReward'; import { useServices } from '@/hooks/useServices'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { + useActiveStakingContractInfo, useStakingContractContext, useStakingContractInfo, } from '@/hooks/useStakingContractInfo'; @@ -145,7 +146,7 @@ const AgentNotRunningButton = () => { const { storeState } = useStore(); const { - isStakingContractInfoLoaded, + isStakingContractInfoRecordLoaded, setIsPaused: setIsStakingContractInfoPollingPaused, updateActiveStakingContractInfo, } = useStakingContractContext(); @@ -153,12 +154,12 @@ const AgentNotRunningButton = () => { const { activeStakingProgramId, defaultStakingProgramId } = useStakingProgram(); - const { - isEligibleForStaking, - isAgentEvicted, - hasEnoughServiceSlots, - isServiceStaked, - } = useStakingContractInfo(activeStakingProgramId ?? defaultStakingProgramId); + const { isEligibleForStaking, isAgentEvicted, isServiceStaked } = + useActiveStakingContractInfo(); + + const { hasEnoughServiceSlots } = useStakingContractInfo( + activeStakingProgramId ?? defaultStakingProgramId, + ); // const minStakingDeposit = // stakingContractInfoRecord?.[activeStakingProgram ?? defaultStakingProgram] @@ -276,7 +277,7 @@ const AgentNotRunningButton = () => { ]); const isDeployable = useMemo(() => { - if (!isStakingContractInfoLoaded) return false; + if (!isStakingContractInfoRecordLoaded) return false; // if the agent is NOT running and the balance is too low, // user should not be able to start the agent @@ -311,7 +312,7 @@ const AgentNotRunningButton = () => { return hasEnoughOlas && hasEnoughEth; }, [ - isStakingContractInfoLoaded, + isStakingContractInfoRecordLoaded, serviceStatus, isLowBalance, requiredOlas, @@ -343,15 +344,12 @@ export const AgentButton = () => { serviceStatus, hasInitialLoaded: isServicesLoaded, } = useServices(); - const { activeStakingProgramId, defaultStakingProgramId } = - useStakingProgram(); - const { isStakingContractInfoLoaded } = useStakingContractContext(); - const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo( - activeStakingProgramId ?? defaultStakingProgramId, - ); + const { isStakingContractInfoRecordLoaded } = useStakingContractContext(); + const { isEligibleForStaking, isAgentEvicted } = + useActiveStakingContractInfo(); return useMemo(() => { - if (!isServicesLoaded || !isStakingContractInfoLoaded) { + if (!isServicesLoaded || !isStakingContractInfoRecordLoaded) { return -
-); - -const AgentStoppingButton = () => ( - -); - -const AgentRunningButton = () => { - const { showNotification } = useElectronApi(); - const { isEligibleForRewards } = useReward(); - const { service, setIsServicePollingPaused, setServiceStatus } = - useServices(); - - const handlePause = useCallback(async () => { - if (!service) return; - // Paused to stop overlapping service poll while waiting for response - setIsServicePollingPaused(true); - - // Optimistically update service status - setServiceStatus(MiddlewareDeploymentStatus.STOPPING); - try { - await ServicesService.stopDeployment(service.hash); - } catch (error) { - console.error(error); - showNotification?.('Error while stopping agent'); - } finally { - // Resume polling, will update to correct status regardless of success - setIsServicePollingPaused(false); - } - }, [service, setIsServicePollingPaused, setServiceStatus, showNotification]); - - return ( - - - - - {isEligibleForRewards ? ( - - Agent is idle  - - - ) : ( - - Agent is working - - )} - - - - ); -}; +import { requiredGas } from '../constants'; /** Button used to start / deploy the agent */ -const AgentNotRunningButton = () => { +export const AgentNotRunningButton = () => { const { wallets, masterSafeAddress } = useWallet(); + const { - service, - serviceStatus, - setServiceStatus, - setIsServicePollingPaused, - updateServicesState, + selectedService, + setPaused: setIsServicePollingPaused, + isLoaded, + refetch: updateServicesState, } = useServices(); + + const { service, deploymentStatus, setDeploymentStatus } = useService({ + serviceConfigId: + isLoaded && selectedService ? selectedService?.service_config_id : '', + }); + const { serviceTemplate } = useServiceTemplates(); const { showNotification } = useElectronApi(); const { @@ -146,16 +53,15 @@ const AgentNotRunningButton = () => { setIsPaused: setIsStakingContractInfoPollingPaused, updateActiveStakingContractInfo, } = useStakingContractInfo(); + const { activeStakingProgramId } = useStakingProgram(); // const minStakingDeposit = // stakingContractInfoRecord?.[activeStakingProgram ?? defaultStakingProgram] // ?.minStakingDeposit; - const requiredOlas = getMinimumStakedAmountRequired( - serviceTemplate, - activeStakingProgramId ?? DEFAULT_STAKING_PROGRAM_ID, - ); + const requiredOlas = + STAKING_PROGRAMS[activeStakingProgramId]?.minStakingDeposit; // TODO: fix activeStakingProgramId const safeOlasBalance = safeBalance?.OLAS; const safeOlasBalanceWithStaked = @@ -177,7 +83,7 @@ const AgentNotRunningButton = () => { setIsStakingContractInfoPollingPaused(true); // Mock "DEPLOYING" status (service polling will update this once resumed) - setServiceStatus(MiddlewareDeploymentStatus.DEPLOYING); + setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYING); // Get the active staking program id; default id if there's no agent yet const stakingProgramId: StakingProgramId = @@ -190,7 +96,7 @@ const AgentNotRunningButton = () => { } } catch (error) { console.error(error); - setServiceStatus(undefined); + setDeploymentStatus(undefined); showNotification?.('Error while creating safe'); setIsStakingContractInfoPollingPaused(false); setIsServicePollingPaused(false); @@ -208,7 +114,7 @@ const AgentNotRunningButton = () => { }); } catch (error) { console.error(error); - setServiceStatus(undefined); + setDeploymentStatus(undefined); showNotification?.('Error while deploying service'); setIsServicePollingPaused(false); setIsBalancePollingPaused(false); @@ -225,7 +131,7 @@ const AgentNotRunningButton = () => { } // Can assume successful deployment - setServiceStatus(MiddlewareDeploymentStatus.DEPLOYED); + setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYED); // TODO: remove this workaround, middleware should respond when agent is staked & confirmed running after `createService` call await delayInSeconds(5); @@ -233,7 +139,7 @@ const AgentNotRunningButton = () => { // update provider states sequentially // service id is required before activeStakingContractInfo & balances can be updated try { - await updateServicesState(); // reload the available services + await updateServicesState?.(); // reload the available services await updateActiveStakingContractInfo(); // reload active staking contract with new service await updateBalances(); // reload the balances } catch (error) { @@ -249,7 +155,7 @@ const AgentNotRunningButton = () => { setIsServicePollingPaused, setIsBalancePollingPaused, setIsStakingContractInfoPollingPaused, - setServiceStatus, + setDeploymentStatus, masterSafeAddress, showNotification, activeStakingProgramId, @@ -263,15 +169,15 @@ const AgentNotRunningButton = () => { // if the agent is NOT running and the balance is too low, // user should not be able to start the agent const isServiceInactive = - serviceStatus === MiddlewareDeploymentStatus.BUILT || - serviceStatus === MiddlewareDeploymentStatus.STOPPED; + deploymentStatus === MiddlewareDeploymentStatus.BUILT || + deploymentStatus === MiddlewareDeploymentStatus.STOPPED; if (isServiceInactive && isLowBalance) { return false; } - if (serviceStatus === MiddlewareDeploymentStatus.DEPLOYED) return false; - if (serviceStatus === MiddlewareDeploymentStatus.DEPLOYING) return false; - if (serviceStatus === MiddlewareDeploymentStatus.STOPPING) return false; + if (deploymentStatus === MiddlewareDeploymentStatus.DEPLOYED) return false; + if (deploymentStatus === MiddlewareDeploymentStatus.DEPLOYING) return false; + if (deploymentStatus === MiddlewareDeploymentStatus.STOPPING) return false; if (!requiredOlas) return false; @@ -290,7 +196,7 @@ const AgentNotRunningButton = () => { return hasEnoughOlas && hasEnoughEth; }, [ - serviceStatus, + deploymentStatus, service, storeState?.isInitialFunded, isEligibleForStaking, @@ -312,47 +218,3 @@ const AgentNotRunningButton = () => { return ; }; - -export const AgentButton = () => { - const { service, serviceStatus, hasInitialLoaded } = useServices(); - const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo(); - - return useMemo(() => { - if (!hasInitialLoaded) { - return + + + {isEligibleForRewards ? ( + + Agent is idle  + + + ) : ( + + Agent is working + + )} + + + + ); +}; diff --git a/frontend/components/MainPage/header/AgentButton/AgentStartingButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentStartingButton.tsx new file mode 100644 index 000000000..6503f6cf6 --- /dev/null +++ b/frontend/components/MainPage/header/AgentButton/AgentStartingButton.tsx @@ -0,0 +1,27 @@ +import { InfoCircleOutlined } from '@ant-design/icons'; +import { Button, Flex, Popover, Typography } from 'antd'; + +import { COLOR } from '@/constants/colors'; + +const LOADING_MESSAGE = + "Starting the agent may take a while, so feel free to minimize the app. We'll notify you once it's running. Please, don't quit the app."; + +export const AgentStartingButton = () => ( + + + + + {LOADING_MESSAGE} + + } + > + + +); diff --git a/frontend/components/MainPage/header/AgentButton/AgentStoppingButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentStoppingButton.tsx new file mode 100644 index 000000000..8fdea7f36 --- /dev/null +++ b/frontend/components/MainPage/header/AgentButton/AgentStoppingButton.tsx @@ -0,0 +1,7 @@ +import { Button } from 'antd'; + +export const AgentStoppingButton = () => ( + +); From 372c0fcf645e0ad8205a90f4ba46dbafd80f2179 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:23:57 +0000 Subject: [PATCH 131/463] refactor: support updated services in useSetupTrayIcon --- frontend/components/MainPage/header/index.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/frontend/components/MainPage/header/index.tsx b/frontend/components/MainPage/header/index.tsx index e5948b576..786af663c 100644 --- a/frontend/components/MainPage/header/index.tsx +++ b/frontend/components/MainPage/header/index.tsx @@ -4,28 +4,32 @@ import { useCallback, useEffect, useState } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; +import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { FirstRunModal } from '../modals/FirstRunModal'; -import { AgentButton } from './AgentButton'; +import { AgentButton } from './AgentButton/AgentButton'; import { AgentHead } from './AgentHead'; const useSetupTrayIcon = () => { const { isLowBalance } = useBalance(); - const { serviceStatus } = useServices(); + const { selectedService } = useServices(); + const { deploymentStatus } = useService({ + serviceConfigId: selectedService?.service_config_id, + }); const { setTrayIcon } = useElectronApi(); useEffect(() => { if (isLowBalance) { setTrayIcon?.('low-gas'); - } else if (serviceStatus === MiddlewareDeploymentStatus.DEPLOYED) { + } else if (deploymentStatus === MiddlewareDeploymentStatus.DEPLOYED) { setTrayIcon?.('running'); - } else if (serviceStatus === MiddlewareDeploymentStatus.STOPPED) { + } else if (deploymentStatus === MiddlewareDeploymentStatus.STOPPED) { setTrayIcon?.('paused'); - } else if (serviceStatus === MiddlewareDeploymentStatus.BUILT) { + } else if (deploymentStatus === MiddlewareDeploymentStatus.BUILT) { setTrayIcon?.('logged-out'); } - }, [isLowBalance, serviceStatus, setTrayIcon]); + }, [isLowBalance, deploymentStatus, setTrayIcon]); return null; }; From cc51de1df17e9cb6a38f2967d1b5d4ecb8acbf8d Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:29:06 +0000 Subject: [PATCH 132/463] release: rc195 --- package.json | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8b9d99e09..517578861 100644 --- a/package.json +++ b/package.json @@ -63,5 +63,5 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc194" + "version": "0.1.0-rc195" } \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index b9f6ca24e..8d66f2f07 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc194" +version = "0.1.0-rc195" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From ded9a09d92a91072a3a66ce657f4600327a7cb74 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:35:50 +0000 Subject: [PATCH 133/463] refactor: migrate button to support new service hooks --- .../StakingContractSection/MigrateButton.tsx | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index f2589d322..4aa288b44 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -8,6 +8,7 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; import { useModals } from '@/hooks/useModals'; import { usePageState } from '@/hooks/usePageState'; +import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; @@ -20,32 +21,41 @@ import { CantMigrateReason, useMigrate } from './useMigrate'; type MigrateButtonProps = { stakingProgramId: StakingProgramId; }; -export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { +export const MigrateButton = ({ + stakingProgramId: stakingProgramIdToMigrateTo, +}: MigrateButtonProps) => { const { goto } = usePageState(); const { serviceTemplate } = useServiceTemplates(); const { - setIsServicePollingPaused, - setServiceStatus, - updateServiceStatus, - hasInitialLoaded: isServicesLoaded, - service, + setPaused: setIsServicePollingPaused, + isLoaded: isServicesLoaded, + selectedService, } = useServices(); + + const { setDeploymentStatus } = useService({ + serviceConfigId: + isServicesLoaded && selectedService + ? selectedService.service_config_id + : '', + }); + const { setIsPaused: setIsBalancePollingPaused } = useBalance(); const { updateActiveStakingProgramId: updateStakingProgram } = useStakingProgram(); const { activeStakingContractInfo } = useStakingContractInfo(); const { setMigrationModalOpen } = useModals(); - const { migrateValidation, firstDeployValidation } = - useMigrate(stakingProgramId); + const { migrateValidation, firstDeployValidation } = useMigrate( + stakingProgramIdToMigrateTo, + ); // if false, user is migrating, not running for first time const isFirstDeploy = useMemo(() => { if (!isServicesLoaded) return false; - if (service) return false; + if (selectedService) return false; return true; - }, [isServicesLoaded, service]); + }, [isServicesLoaded, selectedService]); const validation = isFirstDeploy ? firstDeployValidation : migrateValidation; @@ -77,17 +87,19 @@ export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { setIsBalancePollingPaused(true); try { - setServiceStatus(MiddlewareDeploymentStatus.DEPLOYING); + setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYING); goto(Pages.Main); - await ServicesService.createService({ - stakingProgramId, + // TODO: create type for this response, we need the service_config_id to update the relevant service + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const createServiceResponse = await ServicesService.createService({ + stakingProgramId: stakingProgramIdToMigrateTo, serviceTemplate, deploy: true, useMechMarketplace: false, }); - await updateStakingProgram(); + await updateStakingProgram(); // TODO: refactor to support single staking program & multi staking programs, this on longer works setMigrationModalOpen(true); } catch (error) { @@ -95,7 +107,7 @@ export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { } finally { setIsServicePollingPaused(false); setIsBalancePollingPaused(false); - updateServiceStatus(); + // updateServiceStatus(); // TODO: update service status } }} > From 2870ba67fa11d19e79e2271aff3be6572ef0a0ec Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:36:26 +0000 Subject: [PATCH 134/463] chore: add todo --- .../ManageStakingPage/StakingContractSection/useMigrate.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index 2f4dde07f..33c6507aa 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -53,10 +53,10 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { const stakingContractInfo = stakingContractInfoRecord?.[stakingProgramId]; - const { hasInitialLoaded: isServicesLoaded } = useServices(); + const { isLoaded: isServicesLoaded } = useServices(); const minimumOlasRequiredToMigrate = useMemo( - () => getMinimumStakedAmountRequired(serviceTemplate, stakingProgramId), + () => getMinimumStakedAmountRequired(serviceTemplate, stakingProgramId), // TODO: refactor, can no longer use service template, must use config for funding requirements [serviceTemplate, stakingProgramId], ); From 75c039d7378fea7500b8b5211421290baa8549db Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:37:42 +0000 Subject: [PATCH 135/463] refactor: comment optimus, add todos --- frontend/config/agents.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/frontend/config/agents.ts b/frontend/config/agents.ts index d387c5775..db97cbf2c 100644 --- a/frontend/config/agents.ts +++ b/frontend/config/agents.ts @@ -1,21 +1,26 @@ import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; -import { OptimusService } from '@/service/agents/Optimus'; import { PredictTraderService } from '@/service/agents/PredictTrader'; +// TODO: complete this config +// TODO: add funding requirements + export const AGENT_CONFIG = { [AgentType.PredictTrader]: { name: 'Predict Trader', homeChainId: ChainId.Gnosis, requiresAgentSafesOn: [ChainId.Gnosis], + agentSafeFundingRequirements: { + [ChainId.Gnosis]: 100000000000000000, + }, requiresMasterSafesOn: [ChainId.Gnosis], serviceApi: PredictTraderService, }, - [AgentType.Optimus]: { - name: 'Optimus', - homeChainId: ChainId.Optimism, - requiresAgentSafesOn: [ChainId.Optimism, ChainId.Ethereum, ChainId.Base], - requiresMasterSafesOn: [ChainId.Optimism, ChainId.Ethereum, ChainId.Base], - serviceApi: OptimusService, - }, + // [AgentType.Optimus]: { + // name: 'Optimus', + // homeChainId: ChainId.Optimism, + // requiresAgentSafesOn: [ChainId.Optimism, ChainId.Ethereum, ChainId.Base], + // requiresMasterSafesOn: [ChainId.Optimism, ChainId.Ethereum, ChainId.Base], + // serviceApi: OptimusService, + // }, }; From 68ee3dc256d6a67cb94c0eefbf5f2f93df36431c Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:46:29 +0000 Subject: [PATCH 136/463] refactor: add todos for future improvements and streamline balance fetching logic --- frontend/context/BalanceProvider.tsx | 59 +++++++++++++--------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index eae56b74f..c3fd0da45 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -1,6 +1,7 @@ +// TODO: large refactor needed, provider is way too big, needs to support multiple chains, multiple services, and multiple tokens import { message } from 'antd'; import { isAddress } from 'ethers/lib/utils'; -import { isNumber } from 'lodash'; +import { isNil, isNumber } from 'lodash'; import { ValueOf } from 'next/dist/shared/lib/constants'; import { createContext, @@ -22,9 +23,10 @@ import { LOW_AGENT_SAFE_BALANCE, LOW_MASTER_SAFE_BALANCE, } from '@/constants/thresholds'; +import { ChainId } from '@/enums/Chain'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { TokenSymbol } from '@/enums/Token'; -import { AutonolasService } from '@/service/Autonolas'; +import { StakedAgentService } from '@/service/agents/StakedAgentService'; import { EthersService } from '@/service/Ethers'; import MulticallService from '@/service/Multicall'; import { Address } from '@/types/Address'; @@ -97,10 +99,8 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { const [isBalanceLoaded, setIsBalanceLoaded] = useState(false); const [walletBalances, setWalletBalances] = useState({}); - const [baseBalance, setBaseBalance] = useState(); - const [ethereumBalance, setEthereumBalance] = useState(); - const [optimismBalance, setOptimismBalance] = useState(); + // TODO: refactor to support multiple chains, and gas tokens from config const totalEthBalance: number | undefined = useMemo(() => { if (!isLoaded) return; return Object.values(walletBalances).reduce( @@ -152,28 +152,16 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { } // fetch balances for other chains - try { - const baseBalanceTemp = - EthersService.getBaseBalance(masterEoaAddress).then(setBaseBalance); - - const ethereumBalanceTemp = - EthersService.getEthereumBalance(masterEoaAddress).then( - setEthereumBalance, - ); - - const optimismBalanceTemp = - EthersService.getOptimismBalance(masterEoaAddress).then( - setOptimismBalance, - ); - - await Promise.allSettled([ - baseBalanceTemp, - ethereumBalanceTemp, - optimismBalanceTemp, - ]); - } catch (error) { - console.error(error); - } + // TODO: refactor to dynamically fetch balances for all chains + // try { + // await Promise.allSettled([ + // baseBalanceTemp, + // ethereumBalanceTemp, + // optimismBalanceTemp, + // ]); + // } catch (error) { + // console.error(error); + // } try { const walletBalances = await getWalletBalances(walletAddresses); @@ -181,6 +169,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { setWalletBalances(walletBalances); + // TODO: refactor to use ChainId enum, service from useService(), const serviceId = services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data .token; @@ -191,11 +180,16 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { return; } - if (isAddress(`${masterSafeAddress}`) && serviceId > 0) { + if ( + !isNil(masterSafeAddress) && + isAddress(masterSafeAddress) && + serviceId > 0 + ) { const { depositValue, bondValue, serviceState } = - await AutonolasService.getServiceRegistryInfo( - masterSafeAddress as Address, + await StakedAgentService.getServiceRegistryInfo( + masterSafeAddress, serviceId, + ChainId.Gnosis, // TODO: refactor to get chain id from service ); switch (serviceState) { @@ -234,7 +228,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { message.error('Unable to retrieve wallet balances'); setIsBalanceLoaded(true); } - }, [masterEoaAddress, masterSafeAddress, serviceAddresses, services]); + }, [masterEoaAddress, masterSafeAddress, services]); const agentEoaAddress = useMemo( () => @@ -242,14 +236,17 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { ?.instances?.[0], [services], ); + const masterEoaBalance = useMemo( () => masterEoaAddress && walletBalances[masterEoaAddress], [masterEoaAddress, walletBalances], ); + const masterSafeBalance = useMemo( () => masterSafeAddress && walletBalances[masterSafeAddress], [masterSafeAddress, walletBalances], ); + const agentSafeBalance = useMemo( () => services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data From d9800bc24ba9feda94bc149d702e521d5230db60 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:49:28 +0000 Subject: [PATCH 137/463] refactor: rename selectedServiceUuid to selectedServiceConfigId and update related logic --- frontend/context/ServicesProvider.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 8eec40b9b..38a3cafc9 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -41,7 +41,8 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { const { paused, setPaused, togglePaused } = usePause(); // user selected service identifier - const [selectedServiceUuid, setSelectedServiceUuid] = useState(); + const [selectedServiceConfigId, setSelectedServiceConfigId] = + useState(); const { data: services, @@ -59,17 +60,23 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { const selectedService = useMemo(() => { if (!services) return; - return services.find((service) => service.hash === selectedServiceUuid); // TODO: use uuid instead of hash once middleware refactored - }, [selectedServiceUuid, services]); + return services.find((service) => service.hash === selectedServiceConfigId); // TODO: use uuid instead of hash once middleware refactored + }, [selectedServiceConfigId, services]); const selectService = useCallback((serviceUuid: string) => { - setSelectedServiceUuid(serviceUuid); + setSelectedServiceConfigId(serviceUuid); }, []); + /** + * Select the first service by default + */ useEffect(() => { if (!services) return; - setSelectedServiceUuid(services[0]?.hash); // TODO: use uuid instead of hash once middleware refactored - }, [services]); + if (selectedServiceConfigId) return; + // only select a service by default if services are fetched, but there has been no selection yet + if (isFetched && services.length > 0 && !selectedServiceConfigId) + setSelectedServiceConfigId(services[0].service_config_id); // TODO: use uuid instead of hash once middleware refactored + }, [isFetched, selectedServiceConfigId, services]); // const serviceAddresses = useMemo( // () => From bc9c0db541b2814b9e8ec7912031a4b362495418 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:50:28 +0000 Subject: [PATCH 138/463] feat: add wallet enums, easier to distinguish between what a wallet is, what entity owns it, and enforce types to stop conflicts i.e. running safe functions on an eoa --- frontend/enums/Wallet.ts | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 frontend/enums/Wallet.ts diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts new file mode 100644 index 000000000..f6496c1d8 --- /dev/null +++ b/frontend/enums/Wallet.ts @@ -0,0 +1,9 @@ +export enum WalletType { + Safe = 'multisig', + EOA = 'eoa', +} + +export enum WalletOwner { + Master = 'master', // user + Agent = 'agent', +} From a777e7c74f3e8d9795e39bbe1c9dc4d2b9510fc4 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:56:30 +0000 Subject: [PATCH 139/463] refactor: support multiple services & statuses in useLogs --- frontend/hooks/useLogs.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index c024fc431..45e1b93fd 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -1,6 +1,7 @@ +import { useQueryClient } from '@tanstack/react-query'; import { useMemo } from 'react'; -import { MiddlewareDeploymentStatus } from '@/client'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { useBalance } from './useBalance'; import { useMasterSafe } from './useMasterSafe'; @@ -46,19 +47,24 @@ const useBalancesLogs = () => { }; }; +// TODO: refactor to support logs for multiple services const useServicesLogs = () => { - const { serviceStatus, services, hasInitialLoaded } = useServices(); + const { services, isLoaded } = useServices(); + const { getQueryData } = useQueryClient(); return { - isLoaded: hasInitialLoaded, + isLoaded: isLoaded, data: { - serviceStatus: serviceStatus - ? MiddlewareDeploymentStatus[serviceStatus] - : 'undefined', services: services?.map((item) => ({ ...item, keys: item.keys.map((key) => key.address), + deploymentStatus: getQueryData([ + REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY( + item.service_config_id, + ), + item.service_config_id, + ]), })) ?? 'undefined', }, }; From 2345c457ed7175bdbe8a35c8b9f36bad5d656077 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:56:47 +0000 Subject: [PATCH 140/463] chore: rename keys to have KEY suffix, easier to understand --- frontend/constants/react-query-keys.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index 8c7cb0318..1d5091714 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -1,4 +1,5 @@ export const REACT_QUERY_KEYS = { - SERVICES: ['services'] as const, - SERVICE_STATUS: (uuid: string) => ['serviceStatus', uuid] as const, + SERVICES_KEY: ['services'] as const, + SERVICE_DEPLOYMENT_STATUS_KEY: (serviceConfigId: string) => + ['serviceStatus', serviceConfigId] as const, } as const; From 98a17432d4911db0eb25a1b7ec71425537b6e00e Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:57:01 +0000 Subject: [PATCH 141/463] chore: use renamed react query key --- frontend/context/ServicesProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 38a3cafc9..8ccdb3e4b 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -52,7 +52,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { isFetching, refetch, } = useQuery({ - queryKey: REACT_QUERY_KEYS.SERVICES, + queryKey: REACT_QUERY_KEYS.SERVICES_KEY, queryFn: ServicesService.getServices, enabled: isOnline && !paused, refetchInterval: FIVE_SECONDS_INTERVAL, From 902a3b2f7939538637b907da2566cf4f0a40a6a2 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:57:30 +0000 Subject: [PATCH 142/463] feat: support overwriting service deployment status in reactquery cache --- frontend/hooks/useService.ts | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index 1ab6b48db..b02fcae76 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -1,6 +1,8 @@ +import { useQueryClient } from '@tanstack/react-query'; import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { Address } from '@/types/Address'; import { useServices } from './useServices'; @@ -16,11 +18,12 @@ type ServiceChainIdAddressRecord = { * Hook for interacting with a single service. */ export const useService = ({ - serviceConfigId, + serviceConfigId = '', }: { - serviceConfigId: string; + serviceConfigId?: string; }) => { const { services, isLoaded } = useServices(); + const queryClient = useQueryClient(); const service = useMemo(() => { return services?.find( @@ -55,10 +58,25 @@ export const useService = ({ return addressesByChainId; }, [service]); + /** + * Overrides the deployment status of the service in the cache. + * @note Overwrite is only temporary if ServicesContext is polling + */ + const setDeploymentStatus = (deploymentStatus?: MiddlewareDeploymentStatus) => + queryClient.setQueryData( + REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY(serviceConfigId), + deploymentStatus, + ); + + const deploymentStatus = queryClient.getQueryData< + MiddlewareDeploymentStatus | undefined + >(REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY(serviceConfigId)); + return { service, addresses, - serviceStatus: MiddlewareDeploymentStatus.DEPLOYED, // TODO support other statuses isLoaded, + deploymentStatus, // TODO support other statuses + setDeploymentStatus, }; }; From ec7ea8e5a6a4939cb34527d745862b7dd67ef7a9 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 10:57:42 +0000 Subject: [PATCH 143/463] chore: export services context refetch --- frontend/hooks/useServices.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/hooks/useServices.ts b/frontend/hooks/useServices.ts index 7c36c5627..92967577b 100644 --- a/frontend/hooks/useServices.ts +++ b/frontend/hooks/useServices.ts @@ -86,6 +86,7 @@ export const useServices = () => { setPaused: setPaused, selectedService, selectService, + refetch, } = useContext(ServicesContext); const servicesByChain = useMemo(() => { @@ -115,5 +116,6 @@ export const useServices = () => { paused, selectedService, selectService, + refetch, }; }; From dd9c8d0efb6f47fe0c8d3333f74db38d0d6ed5ef Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 11:19:29 +0000 Subject: [PATCH 144/463] chore: import Address type from local types --- frontend/service/agents/StakedAgentService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/service/agents/StakedAgentService.ts b/frontend/service/agents/StakedAgentService.ts index 837df5d28..a10a34cfc 100644 --- a/frontend/service/agents/StakedAgentService.ts +++ b/frontend/service/agents/StakedAgentService.ts @@ -7,7 +7,6 @@ * @note `noop` functions should be replaced with actual implementations in the extending classes. * @warning DO NOT STORE STATE IN THESE CLASSES. THEY ARE SINGLETONS AND WILL BE SHARED ACROSS THE APPLICATION. */ -import { Address } from 'cluster'; import { ethers } from 'ethers'; import { Contract as MulticallContract } from 'ethers-multicall'; @@ -18,6 +17,7 @@ import { ChainId } from '@/enums/Chain'; import { ContractType } from '@/enums/Contract'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { StakingProgramId } from '@/enums/StakingProgram'; +import { Address } from '@/types/Address'; export const ONE_YEAR = 1 * 24 * 60 * 60 * 365; From 9a841c919d7eab03de91f17b0f1e50f8db07c411 Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Tue, 12 Nov 2024 17:07:05 +0530 Subject: [PATCH 145/463] WIP: Add unified way for environment variables Signed-off-by: OjusWiZard --- frontend/client/types.ts | 12 +++ frontend/constants/serviceTemplates.ts | 113 +++++++++++++------------ operate/operate_types.py | 20 +++++ operate/services/service.py | 9 ++ 4 files changed, 98 insertions(+), 56 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 805909cbd..e7cd26cdd 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -49,6 +49,17 @@ export type Service = { }; }; + +export type EnvProvisionType = "fixed" | "user" | "computed"; + +export type ServiceEnvVariable = { + name: string; + env_variable_name: string; + description: string; + value: string; + provision_type: EnvProvisionType; +} + export type ServiceTemplate = { name: string; hash: string; @@ -57,6 +68,7 @@ export type ServiceTemplate = { service_version: string; home_chain_id: string; configurations: { [key: string]: ConfigurationTemplate }; + env_variables: { [key: string]: ServiceEnvVariable }; deploy?: boolean; }; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 8819b600e..1ce979f6b 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -29,61 +29,62 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ }, }, }, + env_variables: {}, // TODO: add env variables }, -// { -// name: 'Optimus Test', -// hash: 'bafybeibzujtdlgsft3hnjmboa5yfni7vqc2iocjlyti5nadc55jxj3kxbu', -// description: 'Optimus', -// image: -// 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', -// service_version: 'v0.2.9', -// home_chain_id: `${CHAINS.OPTIMISM.chainId}`, -// configurations: { -// [CHAINS.OPTIMISM.chainId]: { -// staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten -// nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', -// // rpc: 'http://localhost:8545', -// agent_id: 40, -// threshold: 1, -// use_staking: true, -// use_mech_marketplace: false, -// cost_of_bond: 1000, -// monthly_gas_estimate: 1000, -// fund_requirements: { -// agent: 1000, -// safe: 1000, -// }, -// }, -// [CHAINS.ETHEREUM.chainId]: { -// staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten -// nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', -// // rpc: 'http://localhost:8545', -// agent_id: 40, -// threshold: 1, -// use_staking: false, -// use_mech_marketplace: false, -// cost_of_bond: 1, -// monthly_gas_estimate: 1000, -// fund_requirements: { -// agent: 1000, -// safe: 1000, -// }, -// }, -// [CHAINS.BASE.chainId]: { -// staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten -// nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', -// // rpc: 'http://localhost:8545', -// agent_id: 40, -// threshold: 1, -// use_staking: false, -// use_mech_marketplace: false, -// cost_of_bond: 1, -// monthly_gas_estimate: 1000, -// fund_requirements: { -// agent: 1000, -// safe: 1000, -// }, -// }, -// }, -// }, + // { + // name: 'Optimus Test', + // hash: 'bafybeibzujtdlgsft3hnjmboa5yfni7vqc2iocjlyti5nadc55jxj3kxbu', + // description: 'Optimus', + // image: + // 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', + // service_version: 'v0.2.9', + // home_chain_id: `${CHAINS.OPTIMISM.chainId}`, + // configurations: { + // [CHAINS.OPTIMISM.chainId]: { + // staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten + // nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', + // // rpc: 'http://localhost:8545', + // agent_id: 40, + // threshold: 1, + // use_staking: true, + // use_mech_marketplace: false, + // cost_of_bond: 1000, + // monthly_gas_estimate: 1000, + // fund_requirements: { + // agent: 1000, + // safe: 1000, + // }, + // }, + // [CHAINS.ETHEREUM.chainId]: { + // staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten + // nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', + // // rpc: 'http://localhost:8545', + // agent_id: 40, + // threshold: 1, + // use_staking: false, + // use_mech_marketplace: false, + // cost_of_bond: 1, + // monthly_gas_estimate: 1000, + // fund_requirements: { + // agent: 1000, + // safe: 1000, + // }, + // }, + // [CHAINS.BASE.chainId]: { + // staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten + // nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', + // // rpc: 'http://localhost:8545', + // agent_id: 40, + // threshold: 1, + // use_staking: false, + // use_mech_marketplace: false, + // cost_of_bond: 1, + // monthly_gas_estimate: 1000, + // fund_requirements: { + // agent: 1000, + // safe: 1000, + // }, + // }, + // }, + // }, ]; diff --git a/operate/operate_types.py b/operate/operate_types.py index aa995c0a0..bd64032be 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -203,7 +203,26 @@ class ConfigurationTemplate(TypedDict): fallback_chain_params: t.Optional[t.Dict] +class ServiceEnvProvisionType(enum.Enum): + """Service environment variable provision type.""" + + FIXED = "fixed" + USER = "user" + COMPUTED = "computed" + + +class ServiceEnvVariable(TypedDict): + """Service environment variable template.""" + + name: str + env_variable_name: str + description: str + value: str + provision_type: ServiceEnvProvisionType + + ConfigurationTemplates = t.Dict[str, ConfigurationTemplate] +ServiceEnvVariables = t.Dict[str, ServiceEnvVariable] class ServiceTemplate(TypedDict): @@ -216,6 +235,7 @@ class ServiceTemplate(TypedDict): service_version: str home_chain_id: str configurations: ConfigurationTemplates + env_variables: ServiceEnvVariables @dataclass diff --git a/operate/services/service.py b/operate/services/service.py index 93e60e3d2..2e2793e10 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -82,6 +82,7 @@ OnChainData, OnChainState, OnChainUserParams, + ServiceEnvVariables, ServiceTemplate, ) from operate.resource import LocalResource @@ -540,6 +541,7 @@ def _build_host(self, force: bool = True, chain_id: str = "100") -> None: encoding="utf-8", ) try: + service.consume_env_variables() builder = ServiceBuilder.from_dir( path=service.service_path, keys_file=keys_file, @@ -654,6 +656,7 @@ class Service(LocalResource): home_chain_id: str chain_configs: ChainConfigs description: str + env_variables: ServiceEnvVariables path: Path service_path: Path @@ -775,6 +778,11 @@ def migrate_format(cls, path: Path) -> bool: return True + def consume_env_variables(self) -> None: + """Consume environment variables.""" + for variable in self.env_variables.values(): + os.environ[variable["env_variable_name"]] = str(variable["value"]) + @classmethod def load(cls, path: Path) -> "Service": """Load a service""" @@ -850,6 +858,7 @@ def new( # pylint: disable=too-many-locals chain_configs=chain_configs, path=service_path.parent, service_path=service_path, + env_variables=service_template["service_env_variables"], ) service.store() return service From 2eddecc67366a7f8dd8686ba2a5a409ef159ff98 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 11:41:51 +0000 Subject: [PATCH 146/463] chore: remove todo comment for useLogs refactor --- frontend/hooks/useLogs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index 45e1b93fd..a6155dabb 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -47,7 +47,6 @@ const useBalancesLogs = () => { }; }; -// TODO: refactor to support logs for multiple services const useServicesLogs = () => { const { services, isLoaded } = useServices(); const { getQueryData } = useQueryClient(); From c32d9c5212b4b2e4a1e504765e2ea9643aaa8543 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 11:49:28 +0000 Subject: [PATCH 147/463] refactor: improve number formatting utility functions and enhance documentation --- frontend/utils/numberFormatters.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/utils/numberFormatters.ts b/frontend/utils/numberFormatters.ts index 1fe86ca22..ceb28dd98 100644 --- a/frontend/utils/numberFormatters.ts +++ b/frontend/utils/numberFormatters.ts @@ -17,7 +17,8 @@ export const balanceFormat = ( /** * Formats larger numbers into small numbers - * i.e. wei to ether `formatUnits('1000000000000000000', 18)` => '1.0' + * @note **divides** the input by 10^decimals + * @example `formatUnits('1000000000000000000', 18)` => '1.0' */ export const formatUnits = (value: BigNumberish, decimals = 18): string => { return ethers.utils.formatUnits(value, decimals); @@ -31,16 +32,20 @@ export const formatEther = (wei: BigNumberish): string => { }; /** - * Parse converts smaller numbers into larger numbers + * Parse converts small numbers into larger numbers + * @note **multiplies** the input by `10 ** decimals` * @example parseUnits('1.0', 18) => '1000000000000000000' */ -export const parseUnits = (value: string, decimals: 18): string => { - return ethers.utils.parseUnits(value, decimals).toString(); +export const parseUnits = ( + value: BigNumberish, + decimals: number = 18, +): string => { + return ethers.utils.parseUnits(`${value}`, decimals).toString(); }; /** * Assumes the input is in ether and converts it to wei */ -export const parseEther = (ether: string | number | bigint): string => { +export const parseEther = (ether: BigNumberish): string => { return ethers.utils.parseEther(`${ether}`).toString(); }; From 0967f32742bf1bdd7dd8262baf1fb936a96397c7 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 11:49:39 +0000 Subject: [PATCH 148/463] chore: remove todo comment for deploymentStatus in useService hook --- frontend/hooks/useService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index b02fcae76..e4a827089 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -76,7 +76,7 @@ export const useService = ({ service, addresses, isLoaded, - deploymentStatus, // TODO support other statuses + deploymentStatus, setDeploymentStatus, }; }; From 9ef2eec340a3909aaf6b93e8d1ced437237d249d Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Tue, 12 Nov 2024 11:53:31 +0000 Subject: [PATCH 149/463] chore: remove todo --- frontend/context/ServicesProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 8ccdb3e4b..0f2ea99b1 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -75,7 +75,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { if (selectedServiceConfigId) return; // only select a service by default if services are fetched, but there has been no selection yet if (isFetched && services.length > 0 && !selectedServiceConfigId) - setSelectedServiceConfigId(services[0].service_config_id); // TODO: use uuid instead of hash once middleware refactored + setSelectedServiceConfigId(services[0].service_config_id); }, [isFetched, selectedServiceConfigId, services]); // const serviceAddresses = useMemo( From 328e9b625c3c99bd30c9fd228bd714c8bb4081e6 Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Tue, 12 Nov 2024 17:53:44 +0530 Subject: [PATCH 150/463] chore: add the latest staking contract from trader Signed-off-by: OjusWiZard --- operate/data/contracts/README.md | 8 ++++++++ operate/data/contracts/staking_token/contract.py | 2 +- operate/data/contracts/staking_token/contract.yaml | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 operate/data/contracts/README.md diff --git a/operate/data/contracts/README.md b/operate/data/contracts/README.md new file mode 100644 index 000000000..eb2ef88f3 --- /dev/null +++ b/operate/data/contracts/README.md @@ -0,0 +1,8 @@ +# Contracts Data + +This directory contains contract packages that are used in the middleware. + +- `staking_token` is copied from [valory/trader](https://github.com/valory-xyz/trader/tree/0f7ac7d77449d434bdc93c703bd3e0e82561eda9/packages/valory/contracts/staking_token) +- `uniswap_v2_erc20` is copied from [valory/optimus-quickstart](https://github.com/valory-xyz/optimus-quickstart/tree/a7e65d2a741bfa749a54d57b80205a477d303cc1/operate/data/contracts/uniswap_v2_erc20) + +TODO: Have a better way to import and reuse these packages accross repositories instead of copying them. diff --git a/operate/data/contracts/staking_token/contract.py b/operate/data/contracts/staking_token/contract.py index 8bc883783..572320f13 100644 --- a/operate/data/contracts/staking_token/contract.py +++ b/operate/data/contracts/staking_token/contract.py @@ -189,4 +189,4 @@ def get_min_staking_duration( """Retrieve the service IDs.""" contract = cls.get_instance(ledger_api, contract_address) duration = contract.functions.minStakingDuration().call() - return dict(data=duration) + return dict(data=duration) \ No newline at end of file diff --git a/operate/data/contracts/staking_token/contract.yaml b/operate/data/contracts/staking_token/contract.yaml index 3cfb1afe9..6441378b6 100644 --- a/operate/data/contracts/staking_token/contract.yaml +++ b/operate/data/contracts/staking_token/contract.yaml @@ -16,8 +16,8 @@ contract_interface_paths: ethereum: build/StakingToken.json dependencies: open-aea-ledger-ethereum: - version: ==1.57.0 + version: <2,>=1.53.0 open-aea-test-autonomy: - version: ==0.16.1 + version: <1,>=0.14.14.post1 web3: version: <7,>=6.0.0 \ No newline at end of file From 184f385716ee2045c26198e4b1df228160bc2ecd Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Tue, 12 Nov 2024 19:06:53 +0530 Subject: [PATCH 151/463] Chore: Update `uniswap_v2_erc20` as in liquidity-rebalancing Signed-off-by: OjusWiZard --- .../contracts/uniswap_v2_erc20/contract.py | 1 + .../contracts/uniswap_v2_erc20/contract.yaml | 4 +- .../uniswap_v2_erc20/tests/__init__.py | 20 + .../uniswap_v2_erc20/tests/test_contract.py | 363 ++++++++++++++++++ 4 files changed, 387 insertions(+), 1 deletion(-) create mode 100644 operate/data/contracts/uniswap_v2_erc20/tests/__init__.py create mode 100644 operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py diff --git a/operate/data/contracts/uniswap_v2_erc20/contract.py b/operate/data/contracts/uniswap_v2_erc20/contract.py index e1fd2f3a9..76a10d8f0 100644 --- a/operate/data/contracts/uniswap_v2_erc20/contract.py +++ b/operate/data/contracts/uniswap_v2_erc20/contract.py @@ -198,6 +198,7 @@ def get_transaction_transfer_logs( # type: ignore # pylint: disable=too-many-a transfer_logs: List = [] if transfer_logs_data: + transfer_logs = cast( List, transfer_logs_data["logs"], diff --git a/operate/data/contracts/uniswap_v2_erc20/contract.yaml b/operate/data/contracts/uniswap_v2_erc20/contract.yaml index 311f5cabc..0c99a3faa 100644 --- a/operate/data/contracts/uniswap_v2_erc20/contract.yaml +++ b/operate/data/contracts/uniswap_v2_erc20/contract.yaml @@ -8,7 +8,9 @@ aea_version: '>=1.0.0, <2.0.0' fingerprint: __init__.py: bafybeia75xbvf6zogcloppdcu2zrwcl6d46ebj2zmm6dkge6eno3k6ysw4 build/IUniswapV2ERC20.json: bafybeid45gy6x5ah5ub5p2obdhph36skpoy5qdhikwwfso7f3655iqnpc4 - contract.py: bafybeiarfpumhdmxh24xuiv6jprjq5f6qlrfrlxisz5enbvvbhotafp37e + contract.py: bafybeidxnb72n5xz4fvvxogbk2xk2vz4jvtsqa3berolr34v7cug3snism + tests/__init__.py: bafybeigj3ngmfmyy4nw4xipxbqnx4nd42aqidqmmduwpx6hurssjqqkirq + tests/test_contract.py: bafybeigaf7kyhuy4qn5dww2r62hffhytab3uhmjummsaiazzvqetvomyi4 fingerprint_ignore_patterns: [] contracts: [] class_name: UniswapV2ERC20Contract diff --git a/operate/data/contracts/uniswap_v2_erc20/tests/__init__.py b/operate/data/contracts/uniswap_v2_erc20/tests/__init__.py new file mode 100644 index 000000000..fb07e2b7d --- /dev/null +++ b/operate/data/contracts/uniswap_v2_erc20/tests/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2021-2022 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests package for valory/uniswap_v2_erc20 contract.""" diff --git a/operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py b/operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py new file mode 100644 index 000000000..5fc9562ef --- /dev/null +++ b/operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py @@ -0,0 +1,363 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2021-2022 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests for valory/uniswap_v2_erc20 contract.""" + +from pathlib import Path +from typing import Dict +from unittest import mock + +from aea.test_tools.test_contract import BaseContractTestCase + +from operate.data.contracts.uniswap_v2_erc20.contract import UniswapV2ERC20Contract + +PACKAGE_DIR = Path(__file__).parent.parent + + +CONTRACT_ADDRESS = "0xa6B71E26C5e0845f74c812102Ca7114b6a896AB2" +ADDRESS_ONE = "0x46F415F7BF30f4227F98def9d2B22ff62738fD68" +ADDRESS_TWO = "0x7A1236d5195e31f1F573AD618b2b6FEFC85C5Ce6" +ADDRESS_THREE = "0x7A1236d5195e31f1F573AD618b2b6FEFC85C5Ce6" +NONCE = 0 +CHAIN_ID = 1 +MAX_ALLOWANCE = 2 ** 256 - 1 + + +class TestUniswapV2ERC20Contract(BaseContractTestCase): + """Test TestUniswapV2ERC20Contract.""" + + path_to_contract = PACKAGE_DIR + ledger_identifier = "ethereum" + contract: UniswapV2ERC20Contract + owner_address = ADDRESS_ONE + sender_address = ADDRESS_TWO + gas_price = 100 + + @classmethod + def finish_contract_deployment(cls) -> str: + """Finish the contract deployment.""" + contract_address = CONTRACT_ADDRESS + return contract_address + + @classmethod + def _deploy_contract(cls, contract, ledger_api, deployer_crypto, gas) -> Dict: # type: ignore + """Deploy contract.""" + return {} + + def test_approve(self) -> None: + """Test approve.""" + eth_value = 0 + gas = 100 + spender_address = ADDRESS_THREE + approval_value = 100 + data = self.contract.get_instance( + self.ledger_api, self.contract_address + ).encodeABI(fn_name="approve", args=[spender_address, approval_value]) + with mock.patch.object( + self.ledger_api.api.eth, "get_transaction_count", return_value=NONCE + ): + with mock.patch.object( + self.ledger_api.api.manager, "request_blocking", return_value=CHAIN_ID + ): + result = self.contract.approve( + self.ledger_api, + self.contract_address, + spender_address, + approval_value, + sender_address=self.sender_address, + gas=gas, + gasPrice=self.gas_price, + ) + assert result == { + "chainId": CHAIN_ID, + "data": data, + "gas": gas, + "gasPrice": self.gas_price, + "nonce": NONCE, + "to": CONTRACT_ADDRESS, + "value": eth_value, + } + + def test_transfer(self) -> None: + """Test transfer.""" + eth_value = 0 + gas = 100 + spender_address = ADDRESS_THREE + value = 100 + data = self.contract.get_instance( + self.ledger_api, self.contract_address + ).encodeABI(fn_name="transfer", args=[spender_address, value]) + with mock.patch.object( + self.ledger_api.api.eth, "get_transaction_count", return_value=NONCE + ): + with mock.patch.object( + self.ledger_api.api.manager, "request_blocking", return_value=CHAIN_ID + ): + result = self.contract.transfer( + self.ledger_api, + self.contract_address, + spender_address, + value, + sender_address=self.sender_address, + gas=gas, + gasPrice=self.gas_price, + ) + assert result == { + "chainId": CHAIN_ID, + "data": data, + "gas": gas, + "gasPrice": self.gas_price, + "nonce": NONCE, + "to": CONTRACT_ADDRESS, + "value": eth_value, + } + + def test_transfer_from(self) -> None: + """Test transfer_from.""" + eth_value = 0 + gas = 100 + from_address = ADDRESS_THREE + to_address = ADDRESS_ONE + value = 100 + data = self.contract.get_instance( + self.ledger_api, self.contract_address + ).encodeABI(fn_name="transferFrom", args=[from_address, to_address, value]) + with mock.patch.object( + self.ledger_api.api.eth, "get_transaction_count", return_value=NONCE + ): + with mock.patch.object( + self.ledger_api.api.manager, "request_blocking", return_value=CHAIN_ID + ): + result = self.contract.transfer_from( + self.ledger_api, + self.contract_address, + from_address, + to_address, + value, + sender_address=self.sender_address, + gas=gas, + gasPrice=self.gas_price, + ) + assert result == { + "chainId": CHAIN_ID, + "data": data, + "gas": gas, + "gasPrice": self.gas_price, + "nonce": NONCE, + "to": CONTRACT_ADDRESS, + "value": eth_value, + } + + def test_permit(self) -> None: + """Test permit.""" + eth_value = 0 + gas = 100 + owner_address = ADDRESS_THREE + spender_address = CONTRACT_ADDRESS + value = 100 + deadline = 10 + v = 10 + r = b"" + s = b"" + data = self.contract.get_instance( + self.ledger_api, self.contract_address + ).encodeABI( + fn_name="permit", + args=[owner_address, spender_address, value, deadline, v, r, s], + ) + with mock.patch.object( + self.ledger_api.api.eth, "get_transaction_count", return_value=NONCE + ): + with mock.patch.object( + self.ledger_api.api.manager, "request_blocking", return_value=CHAIN_ID + ): + result = self.contract.permit( + self.ledger_api, + self.contract_address, + owner_address, + spender_address, + value, + deadline, + v, + r, + s, + sender_address=self.sender_address, + gas=gas, + gasPrice=self.gas_price, + ) + assert result == { + "chainId": CHAIN_ID, + "data": data, + "gas": gas, + "gasPrice": self.gas_price, + "nonce": NONCE, + "to": CONTRACT_ADDRESS, + "value": eth_value, + } + + def test_allowance(self) -> None: + """Test allowance.""" + owner_address = ADDRESS_ONE + spender_address = ADDRESS_THREE + with mock.patch.object( + self.ledger_api.api.manager, + "request_blocking", + return_value="0x0000000000000000000000000000000000000000000000000000000000000000", + ): + result = self.contract.allowance( + self.ledger_api, + self.contract_address, + owner_address, + spender_address, + ) + assert result == 0 + + def test_balance_of(self) -> None: + """Test balance_of.""" + owner_address = ADDRESS_THREE + with mock.patch.object( + self.ledger_api.api.manager, + "request_blocking", + return_value="0x0000000000000000000000000000000000000000000000000000000000000000", + ): + result = self.contract.balance_of( + self.ledger_api, self.contract_address, owner_address + ) + assert result == 0 + + def test_get_approve_data(self) -> None: + """Test get_method_data with approve.""" + + result = self.contract.get_method_data( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + method_name="approve", + spender=ADDRESS_ONE, + value=MAX_ALLOWANCE, + ) + assert result == { + "data": b"\t^\xa7\xb3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"F\xf4\x15\xf7\xbf0\xf4\"\x7f\x98\xde\xf9\xd2\xb2/\xf6'8\xfdh" + b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + b"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" + } + + def test_get_transfer_data(self) -> None: + """Test get_method_data with transfer.""" + + result = self.contract.get_method_data( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + method_name="transfer", + to=ADDRESS_ONE, + value=1, + ) + assert result == { + "data": b"\xa9\x05\x9c\xbb\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"F\xf4\x15\xf7\xbf0\xf4\"\x7f\x98\xde\xf9\xd2\xb2/\xf6'8\xfdh" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01" + } + + def test_get_transfer_from_data(self) -> None: + """Test get_method_data with transfer_from.""" + + # "from" is a reserved word, so must be passed as kwargs + kwargs = {"from": ADDRESS_TWO, "to": ADDRESS_ONE, "value": 1} + + result = self.contract.get_method_data( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + method_name="transfer_from", + **kwargs + ) + assert result == { + "data": b"#\xb8r\xdd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\x126\xd5" + b"\x19^1\xf1\xf5s\xada\x8b+o\xef\xc8\\\\\xe6\x00\x00\x00\x00" + b'\x00\x00\x00\x00\x00\x00\x00\x00F\xf4\x15\xf7\xbf0\xf4"' + b"\x7f\x98\xde\xf9\xd2\xb2/\xf6'8\xfdh\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x01" + } + + def test_get_permit_data(self) -> None: + """Test get_method_data with permit.""" + + result = self.contract.get_method_data( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + method_name="permit", + owner=ADDRESS_ONE, + spender=ADDRESS_TWO, + value=1, + deadline=300, + v=0, + r=b"0", + s=b"0", + ) + + assert result == { + "data": b"\xd5\x05\xac\xcf\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"F\xf4\x15\xf7\xbf0\xf4\"\x7f\x98\xde\xf9\xd2\xb2/\xf6'8\xfdh" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\x126\xd5\x19^1\xf1" + b"\xf5s\xada\x8b+o\xef\xc8\\\\\xe6\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x01,\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"\x00\x00\x00\x00\x00\x00\x00\x00" + } + + def test_get_allowance_data(self) -> None: + """Test get_method_data with allowance.""" + + result = self.contract.get_method_data( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + method_name="allowance", + owner=ADDRESS_ONE, + spender=ADDRESS_TWO, + ) + + assert result == { + "data": b"\xddb\xed>\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"F\xf4\x15\xf7\xbf0\xf4\"\x7f\x98\xde\xf9\xd2\xb2/\xf6'8\xfdh" + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00z\x126\xd5\x19^1\xf1" + b"\xf5s\xada\x8b+o\xef\xc8\\\\\xe6" + } + + def test_get_balance_of_data(self) -> None: + """Test get_method_data with balance_of.""" + + result = self.contract.get_method_data( + ledger_api=self.ledger_api, + contract_address=self.contract_address, + method_name="balance_of", + owner=ADDRESS_ONE, + ) + + assert result == { + "data": b"p\xa0\x821\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + b"F\xf4\x15\xf7\xbf0\xf4\"\x7f\x98\xde\xf9\xd2\xb2/\xf6'8\xfdh" + } From 3b4186d210718ca9f7d500ce1f878b72693b9354 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 17:25:18 +0100 Subject: [PATCH 152/463] feat: migrate wallet functionality --- operate/cli.py | 4 +++ operate/wallet/master.py | 56 +++++++++++++++++++++++++++++++++------- 2 files changed, 50 insertions(+), 10 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index e4ccf733c..ad558430e 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -161,6 +161,10 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st logger.info("Migrating service configs done.") operate.service_manager().log_directories() + logger.info("Migrating wallet configs...") + operate.wallet_manager.migrate_wallet_configs() + logger.info("Migrating wallet configs done.") + funding_jobs: t.Dict[str, asyncio.Task] = {} health_checker = HealthChecker( operate.service_manager(), number_of_fails=number_of_fails diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 2bf16fcc8..0f3c852fd 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -22,11 +22,13 @@ import json import os import typing as t +import logging from dataclasses import dataclass, field from pathlib import Path from aea.crypto.base import Crypto, LedgerApi from aea.crypto.registries import make_ledger_api +from aea.helpers.logging import setup_logger from aea_ledger_ethereum.ethereum import EthereumApi, EthereumCrypto from autonomy.chain.config import ChainType as ChainProfile from autonomy.chain.tx import TxSettler @@ -52,6 +54,7 @@ class MasterWallet(LocalResource): path: Path safes: t.Optional[t.Dict[ChainType, str]] = {} + safe_chains: t.List[ChainType] = [] ledger_type: LedgerType _key: str @@ -161,17 +164,21 @@ def add_or_swap_owner( """Add or swap backup owner.""" raise NotImplementedError() + @classmethod + def migrate_format(cls, path: Path) -> bool: + """Migrate the JSON file format if needed.""" + raise NotImplementedError + @dataclass class EthereumMasterWallet(MasterWallet): """Master wallet manager.""" - path: Path address: str - safe_chains: t.List[ChainType] # For cross-chain support - ledger_type: LedgerType = LedgerType.ETHEREUM safes: t.Optional[t.Dict[ChainType, str]] = field(default_factory=dict) # type: ignore + safe_chains: t.List[ChainType] = field(default_factory=list) # type: ignore + ledger_type: LedgerType = LedgerType.ETHEREUM safe_nonce: t.Optional[int] = None # For cross-chain reusability _file = ledger_type.config_file @@ -417,13 +424,28 @@ def add_or_swap_owner( @classmethod def load(cls, path: Path) -> "EthereumMasterWallet": """Load master wallet.""" - raw_ethereum_wallet = super().load(path) # type: ignore - safes = {} - for id_, safe_address in raw_ethereum_wallet.safes.items(): # type: ignore - safes[ChainType(int(id_))] = safe_address + return super().load(path) # type: ignore + + @classmethod + def migrate_format(cls, path: Path) -> bool: + """Migrate the JSON file format if needed.""" + wallet_path = path / cls._file + with open(wallet_path, "r", encoding="utf-8") as file: + data = json.load(file) + + migrated = False + if "safes" not in data: + safes = {} + for chain in data["safe_chains"]: + safes[chain] = data["safe"] + data.pop("safe") + data["safes"] = safes + migrated = True - raw_ethereum_wallet.safes = safes # type: ignore - return t.cast(EthereumMasterWallet, raw_ethereum_wallet) + with open(wallet_path, "w", encoding="utf-8") as file: + json.dump(data, file, indent=2) + + return migrated LEDGER_TYPE_TO_WALLET_CLASS = { @@ -434,10 +456,11 @@ def load(cls, path: Path) -> "EthereumMasterWallet": class MasterWalletManager: """Master wallet manager.""" - def __init__(self, path: Path, password: t.Optional[str] = None) -> None: + def __init__(self, path: Path, password: t.Optional[str] = None, logger: t.Optional[logging.Logger] = None) -> None: """Initialize master wallet manager.""" self.path = path self._password = password + self.logger = logger or setup_logger(name="operate.master_wallet_manager") @property def json(self) -> t.List[t.Dict]: @@ -503,3 +526,16 @@ def __iter__(self) -> t.Iterator[MasterWallet]: if not self.exists(ledger_type=ledger_type): continue yield LEDGER_TYPE_TO_WALLET_CLASS[ledger_type].load(path=self.path) + + def migrate_wallet_configs(self) -> None: + """Migrate old wallet config formats to new ones, if applies.""" + + print(self.path) + + for ledger_type in LedgerType: + if not self.exists(ledger_type=ledger_type): + continue + wallet_class = LEDGER_TYPE_TO_WALLET_CLASS[ledger_type] + migrated = wallet_class.migrate_format(path=self.path) + if migrated: + self.logger.info(f"Wallet {wallet_class} has been migrated.") From 6a5e4d7a4d1829fefa1450bd2a98c14e2f2ee9e7 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 18:21:25 +0100 Subject: [PATCH 153/463] chore: update safes dictionary --- operate/wallet/master.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 0f3c852fd..f19d3f560 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -174,6 +174,7 @@ def migrate_format(cls, path: Path) -> bool: class EthereumMasterWallet(MasterWallet): """Master wallet manager.""" + path: Path address: str safes: t.Optional[t.Dict[ChainType, str]] = field(default_factory=dict) # type: ignore @@ -424,7 +425,17 @@ def add_or_swap_owner( @classmethod def load(cls, path: Path) -> "EthereumMasterWallet": """Load master wallet.""" - return super().load(path) # type: ignore + # TODO: This is a complex way to read the 'safes' dictionary. + # The reason for that is that wallet.safes[chain_type] would fail + # (for example in service manager) when passed a ChainType key. + + raw_ethereum_wallet = super().load(path) # type: ignore + safes = {} + for id_, safe_address in raw_ethereum_wallet.safes.items(): # type: ignore + safes[ChainType(int(id_))] = safe_address + + raw_ethereum_wallet.safes = safes # type: ignore + return t.cast(EthereumMasterWallet, raw_ethereum_wallet) @classmethod def migrate_format(cls, path: Path) -> bool: From 8c8ca3af89b8a22f33bf85212ead08ce7d33a225 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 18:21:41 +0100 Subject: [PATCH 154/463] chore: add missing ABI --- .../staking_token/build/StakingToken.json | 1336 +++++++++++++++++ 1 file changed, 1336 insertions(+) create mode 100644 operate/data/contracts/staking_token/build/StakingToken.json diff --git a/operate/data/contracts/staking_token/build/StakingToken.json b/operate/data/contracts/staking_token/build/StakingToken.json new file mode 100644 index 000000000..070508dba --- /dev/null +++ b/operate/data/contracts/staking_token/build/StakingToken.json @@ -0,0 +1,1336 @@ +{ + "_format": "hh-sol-artifact-1", + "contractName": "StakingToken", + "sourceName": "contracts/staking/StakingToken.sol", + "abi": [ + { + "inputs": [], + "name": "AlreadyInitialized", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "activityChecker", + "type": "address" + } + ], + "name": "ContractOnly", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + } + ], + "name": "LowerThan", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "maxNumServices", + "type": "uint256" + } + ], + "name": "MaxNumServicesReached", + "type": "error" + }, + { + "inputs": [], + "name": "NoRewardsAvailable", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tsProvided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "tsExpected", + "type": "uint256" + } + ], + "name": "NotEnoughTimeStaked", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnerOnly", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "ServiceNotUnstaked", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "TokenTransferFailed", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + } + ], + "name": "UnauthorizedMultisig", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "provided", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "expected", + "type": "uint256" + } + ], + "name": "ValueLowerThan", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "agentId", + "type": "uint256" + } + ], + "name": "WrongAgentId", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongServiceConfiguration", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "state", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "WrongServiceState", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "expected", + "type": "address" + }, + { + "internalType": "address", + "name": "provided", + "type": "address" + } + ], + "name": "WrongStakingToken", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroTokenAddress", + "type": "error" + }, + { + "inputs": [], + "name": "ZeroValue", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "availableRewards", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "serviceIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "rewards", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "epochLength", + "type": "uint256" + } + ], + "name": "Checkpoint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "availableRewards", + "type": "uint256" + } + ], + "name": "Deposit", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "nonces", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "name": "RewardClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "nonces", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "availableRewards", + "type": "uint256" + } + ], + "name": "ServiceForceUnstaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "serviceInactivity", + "type": "uint256" + } + ], + "name": "ServiceInactivityWarning", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "nonces", + "type": "uint256[]" + } + ], + "name": "ServiceStaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "nonces", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "availableRewards", + "type": "uint256" + } + ], + "name": "ServiceUnstaked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "epoch", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "serviceIds", + "type": "uint256[]" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "owners", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "address[]", + "name": "multisigs", + "type": "address[]" + }, + { + "indexed": false, + "internalType": "uint256[]", + "name": "serviceInactivity", + "type": "uint256[]" + } + ], + "name": "ServicesEvicted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdraw", + "type": "event" + }, + { + "inputs": [], + "name": "VERSION", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "activityChecker", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "agentIds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "availableRewards", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "balance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "calculateStakingLastReward", + "outputs": [ + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "calculateStakingReward", + "outputs": [ + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "checkpoint", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "evictServiceIds", + "type": "uint256[]" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "checkpointAndClaim", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "claim", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "configHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "deposit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "emissionsAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "epochCounter", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "forcedUnstake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getAgentIds", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getNextRewardCheckpointTimestamp", + "outputs": [ + { + "internalType": "uint256", + "name": "tsNext", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getServiceIds", + "outputs": [ + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getServiceInfo", + "outputs": [ + { + "components": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "nonces", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "tsStart", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "inactivity", + "type": "uint256" + } + ], + "internalType": "struct ServiceInfo", + "name": "sInfo", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "getStakingState", + "outputs": [ + { + "internalType": "enum StakingBase.StakingState", + "name": "stakingState", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "components": [ + { + "internalType": "bytes32", + "name": "metadataHash", + "type": "bytes32" + }, + { + "internalType": "uint256", + "name": "maxNumServices", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardsPerSecond", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minStakingDeposit", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "minNumStakingPeriods", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "maxNumInactivityPeriods", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "livenessPeriod", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "timeForEmissions", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "numAgentInstances", + "type": "uint256" + }, + { + "internalType": "uint256[]", + "name": "agentIds", + "type": "uint256[]" + }, + { + "internalType": "uint256", + "name": "threshold", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "configHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "proxyHash", + "type": "bytes32" + }, + { + "internalType": "address", + "name": "serviceRegistry", + "type": "address" + }, + { + "internalType": "address", + "name": "activityChecker", + "type": "address" + } + ], + "internalType": "struct StakingBase.StakingParams", + "name": "_stakingParams", + "type": "tuple" + }, + { + "internalType": "address", + "name": "_serviceRegistryTokenUtility", + "type": "address" + }, + { + "internalType": "address", + "name": "_stakingToken", + "type": "address" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "livenessPeriod", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "mapServiceInfo", + "outputs": [ + { + "internalType": "address", + "name": "multisig", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "uint256", + "name": "tsStart", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "reward", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "inactivity", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxInactivityDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxNumInactivityPeriods", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "maxNumServices", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "metadataHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minStakingDeposit", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "minStakingDuration", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "numAgentInstances", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "proxyHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardsPerSecond", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "serviceRegistry", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "serviceRegistryTokenUtility", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "name": "setServiceIds", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "stakingToken", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "threshold", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "timeForEmissions", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "tsCheckpoint", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "serviceId", + "type": "uint256" + } + ], + "name": "unstake", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "function" + } + ], + "bytecode": "0x608060405234801561000f575f80fd5b50600436106102cd575f3560e01c806393ac752f1161017c578063c5a1d7f0116100dd578063eb338c9611610093578063f86ad2b61161006e578063f86ad2b6146105db578063fd0bba8c146105e4578063ffa1ad7414610604575f80fd5b8063eb338c96146105b8578063f189e85a146105cb578063f4dce714146105d3575f80fd5b8063e1f1176d116100c3578063e1f1176d1461059d578063e77cdcc9146105a6578063eacdaabc146105af575f80fd5b8063c5a1d7f014610582578063cbcf252a1461058a575f80fd5b8063b150876011610132578063b69ef8a811610118578063b69ef8a81461054e578063b6b55f2514610557578063c2c4c5c11461056a575f80fd5b8063b150876014610526578063b267c67b1461053b575f80fd5b8063a0ed60e011610162578063a0ed60e01461048f578063a694fc3a14610498578063a74466ad146104ab575f80fd5b806393ac752f146104715780639573236114610486575f80fd5b806352c824f5116102315780637fbe2833116101e757806383f9eb22116101c257806383f9eb2214610442578063879d9090146104555780638f9e0a621461045e575f80fd5b80637fbe283314610406578063809cee2f1461041957806382a8ea5814610422575f80fd5b806356e760581161021757806356e76058146103d75780635829c5ec146103ea57806372f702f3146103f3575f80fd5b806352c824f5146103bb578063546af2e0146103c4575f80fd5b80632871405111610286578063379607f51161026c578063379607f5146103965780633e732997146103a957806342cde4e8146103b2575f80fd5b806328714051146103585780632e17de7814610383575f80fd5b8063150b7a02116102b6578063150b7a02146102f657806316a75172146103465780631f7794081461034f575f80fd5b806308ae7e54146102d157806314b19c5a146102ed575b5f80fd5b6102da600d5481565b6040519081526020015b60405180910390f35b6102da600f5481565b610315610304366004612c65565b630a85bd0160e11b95945050505050565b6040517fffffffff0000000000000000000000000000000000000000000000000000000090911681526020016102e4565b6102da60015481565b6102da60065481565b60175461036b906001600160a01b031681565b6040516001600160a01b0390911681526020016102e4565b6102da610391366004612cfc565b610635565b6102da6103a4366004612cfc565b610646565b6102da60135481565b6102da60085481565b6102da60055481565b6102da6103d2366004612cfc565b610651565b6102da6103e5366004612cfc565b61065d565b6102da60075481565b60185461036b906001600160a01b031681565b6102da610414366004612cfc565b61067c565b6102da600a5481565b610435610430366004612cfc565b610743565b6040516102e49190612d13565b6102da610450366004612cfc565b610832565b6102da60115481565b600c5461036b906001600160a01b031681565b61048461047f366004612cfc565b6108ea565b005b6102da60125481565b6102da60045481565b6104846104a6366004612cfc565b6108f9565b6104f36104b9366004612cfc565b60156020525f9081526040902080546001820154600383015460048401546005909401546001600160a01b03938416949390921692909185565b604080516001600160a01b039687168152959094166020860152928401919091526060830152608082015260a0016102e4565b61052e610de9565b6040516102e49190612ddf565b610484610549366004612f13565b610e3f565b6102da60105481565b610484610565366004612cfc565b610eb5565b610572610f42565b6040516102e49493929190613047565b6102da5f5481565b600b5461036b906001600160a01b031681565b6102da60095481565b6102da60035481565b6102da60025481565b6102da6105c6366004612cfc565b6115d6565b61052e6115e5565b6102da611639565b6102da600e5481565b6105f76105f2366004612cfc565b61164f565b6040516102e491906130b2565b610628604051806040016040528060058152602001640302e322e360dc1b81525081565b6040516102e491906130d8565b5f610640825f611721565b92915050565b5f610640825f611aa8565b5f610640826001611aa8565b6014818154811061066c575f80fd5b5f91825260209091200154905081565b5f818152601560209081526040808320815160c08101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287969395860193909291908301828280156106f957602002820191905f5260205f20905b8154815260200190600101908083116106e5575b50505050508152602001600382015481526020016004820154815260200160058201548152505090508060800151915061073283610832565b61073c9083613121565b9392505050565b6107896040518060c001604052805f6001600160a01b031681526020015f6001600160a01b03168152602001606081526020015f81526020015f81526020015f81525090565b5f82815260156020908152604091829020825160c08101845281546001600160a01b039081168252600183015416818401526002820180548551818602810186018752818152929593949386019383018282801561080457602002820191905f5260205f20905b8154815260200190600101908083116107f0575b5050505050815260200160038201548152602001600482015481526020016005820154815250509050919050565b5f805f805f80610840611bab565b505050945094509450945094505f5b848110156108df578783828151811061086a5761086a613134565b6020026020010151036108d757858411156108b657838683838151811061089357610893613134565b60200260200101516108a59190613148565b6108af9190613173565b96506108df565b8181815181106108c8576108c8613134565b602002602001015196506108df565b60010161084f565b505050505050919050565b6108f5816001611721565b5050565b610901610f42565b505050506011545f036109275760405163afb0be3360e01b815260040160405180910390fd5b5f81815260156020526040902060038101541561095f5760405163b4817ce760e01b8152600481018390526024015b60405180910390fd5b601654600154810361098a5760015460405163fd20861560e01b815260040161095691815260200190565b600b5460405163ef0e239b60e01b8152600481018590525f916001600160a01b03169063ef0e239b906024015f60405180830381865afa1580156109d0573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526109f79190810190613230565b9050806080015163ffffffff1660075414610a2857604051637ad404bf60e11b815260048101859052602401610956565b60095415801590610a3f5750806040015160095414155b15610a6057604051637ad404bf60e11b815260048101859052602401610956565b5f600854118015610a7d5750806060015163ffffffff1660085414155b15610a9e57604051637ad404bf60e11b815260048101859052602401610956565b60048160c001516005811115610ab657610ab661309e565b14610af5578060c001516005811115610ad157610ad161309e565b604051633c053f9d60e21b8152600481019190915260248101859052604401610956565b5f81602001516001600160a01b0316803b806020016040519081016040528181525f908060200190933c80519060200120905080600a5414610b5a57602082015160405162a2307960e51b81526001600160a01b039091166004820152602401610956565b6014548015610c1e5760e083015151818114610b8c57604051637ad404bf60e11b815260048101889052602401610956565b5f5b81811015610c1b578460e001518181518110610bac57610bac613134565b602002602001015163ffffffff1660148281548110610bcd57610bcd613134565b905f5260205f20015414610c135760148181548110610bee57610bee613134565b905f5260205f200154604051632ab10b0b60e21b815260040161095691815260200190565b600101610b8e565b50505b610c3e86845f01516bffffffffffffffffffffffff168560e00151611f4b565b602083015185546001600160a01b039182166001600160a01b0319918216811788556001880180549092163317909155600c5460405163d564c4bf60e01b815260048101929092525f92169063d564c4bf906024015f60405180830381865afa158015610cad573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610cd49190810190613309565b8051909150610cec9060028801906020840190612bc6565b50426003870155601680546001810182555f919091527fd833147d7dc355ba459fc788f669e58cfaf9dc25ddcd0702e87d69c7b512428901879055600b54604051632142170760e11b8152336004820152306024820152604481018990526001600160a01b03909116906342842e0e906064015f604051808303815f87803b158015610d76575f80fd5b505af1158015610d88573d5f803e3d5ffd5b5050505083602001516001600160a01b0316336001600160a01b0316887faa6b005b4958114a0c90492461c24af6525ae0178db7fbf44125ae9217c69ccb600f5485604051610dd892919061338a565b60405180910390a450505050505050565b60606014805480602002602001604051908101604052809291908181526020018280548015610e3557602002820191905f5260205f20905b815481526020019060010190808311610e21575b5050505050905090565b610e4883612134565b6001600160a01b0381161580610e6557506001600160a01b038216155b15610e8357604051636b093aad60e01b815260040160405180910390fd5b601880546001600160a01b039283166001600160a01b0319918216179091556017805493909216921691909117905550565b5f81601054610ec49190613121565b90505f82601154610ed59190613121565b60108390556011819055601854909150610efa906001600160a01b03163330866124b2565b604080518481526020810184905290810182905233907f36af321ec8d3c75236829c5317affd40ddb308863a1236d2d277a4025cccee1e9060600160405180910390a2505050565b6060806060805f805f805f805f80610f58611bab565b97509750975097509750975097509750606080845167ffffffffffffffff811115610f8557610f85612df1565b604051908082528060200260200182016040528015610fae578160200160208202803683370190505b509a505f891561132f578967ffffffffffffffff811115610fd157610fd1612df1565b604051908082528060200260200182016040528015610ffa578160200160208202803683370190505b5092508967ffffffffffffffff81111561101657611016612df1565b60405190808252806020026020018201604052801561103f578160200160208202803683370190505b5091508a89111561123c575f8060015b8c811015611138578b8e8b838151811061106b5761106b613134565b602002602001015161107d9190613148565b6110879190613173565b92506110938383613121565b91508a81815181106110a7576110a7613134565b602002602001015193508a81815181106110c3576110c3613134565b60200260200101518682815181106110dd576110dd613134565b602002602001018181525050828582815181106110fc576110fc613134565b6020026020010181815250508260155f8681526020019081526020015f206004015f82825461112b9190613121565b909155505060010161104f565b508a8d8a5f8151811061114d5761114d613134565b602002602001015161115f9190613148565b6111699190613173565b91506111758282613121565b9050895f8151811061118957611189613134565b60200260200101519250895f815181106111a5576111a5613134565b6020026020010151855f815181106111bf576111bf613134565b602002602001018181525050808d11156111ea576111dd818e6133aa565b6111e79083613121565b91505b81845f815181106111fd576111fd613134565b6020026020010181815250508160155f8581526020019081526020015f206004015f82825461122c9190613121565b909155505f9d5061132992505050565b5f5b8a81101561131b5788818151811061125857611258613134565b6020026020010151915088818151811061127457611274613134565b602002602001015184828151811061128e5761128e613134565b6020026020010181815250508781815181106112ac576112ac613134565b60200260200101518382815181106112c6576112c6613134565b6020026020010181815250508781815181106112e4576112e4613134565b602002602001015160155f8481526020019081526020015f206004015f82825461130e9190613121565b909155505060010161123e565b50611326898c6133aa565b9a505b60118b90555b8551156115a257600f545f9a508a5b875181101561151d5787818151811061135957611359613134565b6020026020010151925086818151811061137557611375613134565b602002602001015160155f8581526020019081526020015f2060020190805190602001906113a4929190612bc6565b505f8682815181106113b8576113b8613134565b60200260200101511115611503578581815181106113d8576113d8613134565b602002602001015160155f8581526020019081526020015f20600501546113ff9190613121565b86828151811061141157611411613134565b60200260200101818152505085818151811061142f5761142f613134565b602002602001015160155f8581526020019081526020015f2060050181905550600e5486828151811061146457611464613134565b602002602001015111156114a257828e828151811061148557611485613134565b60209081029190910101528b61149a816133bd565b9c5050611515565b827f33dc5cdf1e035de8a7fe16ad7a30a441d30ee51719d3f07703ee35d4348f0779838884815181106114d7576114d7613134565b60200260200101516040516114f6929190918252602082015260400190565b60405180910390a2611515565b5f838152601560205260408120600501555b60010161133e565b508a156115365761152f8d868d612536565b9c5061153b565b60609c505b5f6013544261154a91906133aa565b42601355905061155b826001613121565b600f81905550817f48b735a18ed32318d316214e41387be29c52e29df4598f2b8e40fa843be3f9408e87878560405161159794939291906133d5565b60405180910390a250505b855115806115b057505f8c51115b156115c0576115bd6115e5565b95505b50939c509a509198505050505050505090919293565b6016818154811061066c575f80fd5b60606016805480602002602001604051908101604052809291908181526020018280548015610e3557602002820191905f5260205f2090815481526020019060010190808311610e21575050505050905090565b5f60055460135461164a9190613121565b905090565b5f818152601560209081526040808320815160c08101835281546001600160a01b03908116825260018301541681850152600282018054845181870281018701865281815287969395860193909291908301828280156116cc57602002820191905f5260205f20905b8154815260200190600101908083116116b8575b5050505050815260200160038201548152602001600482015481526020016005820154815250509050600e548160a00151111561170c576002915061171b565b60608101511561171b57600191505b50919050565b5f82815260156020526040812060018101546001600160a01b0316331461177257600181015460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610956565b5f61177b610f42565b505050600483015460115460038501549195509192505f9061179d90426133aa565b9050600d5481111580156117b057505f82115b156117e357600d5460405163ba2bbc6b60e01b815260048101899052602481018390526044810191909152606401610956565b5f805b8451821015611822578885838151811061180257611802613134565b60200260200101510361181757506001611822565b8160010191506117e6565b5f8660020180548060200260200160405190810160405280929190818152602001828054801561186f57602002820191905f5260205f20905b81548152602001906001019080831161185b575b50508a545f8f815260156020526040812080546001600160a01b0319908116825560018201805490911690559596506001600160a01b0390911694935091506118bd90506002830182612c0f565b505f60038201819055600482018190556005909101558215611953576016545f906118ea906001906133aa565b9050801561192d576016818154811061190557611905613134565b905f5260205f2001546016868154811061192157611921613134565b5f918252602090912001555b601680548061193e5761193e613411565b600190038181905f5260205f20015f90559055505b600b546040516323b872dd60e01b8152306004820152336024820152604481018d90526001600160a01b03909116906323b872dd906064015f604051808303815f87803b1580156119a2575f80fd5b505af11580156119b4573d5f803e3d5ffd5b505050505f8911156119e65789156119dc576119d08987613121565b601181905595506119e6565b6119e6818a6128ee565b8915611a4557806001600160a01b0316336001600160a01b03168c7f91c9f7c7f307bcc0ae02ba613bd8d07c29e94952f0a28803ded176fcd7d96d64600f54868e8c604051611a389493929190613425565b60405180910390a4611a9a565b806001600160a01b0316336001600160a01b03168c7f6d789d063e079a4c156e77a20008529fc448dca2cd7e5e7a20abf969fffb9226600f54868e8c604051611a919493929190613425565b60405180910390a45b505050505050505092915050565b5f82815260156020526040812060018101546001600160a01b03163314611af957600181015460405163521eb56d60e11b81523360048201526001600160a01b039091166024820152604401610956565b8215611b0c57611b07610f42565b505050505b80600401549150815f03611b3357604051637c946ed760e01b815260040160405180910390fd5b5f600482015580546001600160a01b0316611b4e81846128ee565b806001600160a01b0316336001600160a01b0316867f31add0166dae59ea66bbc180e4fae85b72fc9b7b5fc7b0f7257e4721a840c96e600f548660020188604051611b9b93929190613450565b60405180910390a4505092915050565b60135460115460165490915f91829160609182918291829182918015801590611bdf5750600554611bdc83426133aa565b10155b8015611bea57505f8a115b15611f3f578067ffffffffffffffff811115611c0857611c08612df1565b604051908082528060200260200182016040528015611c31578160200160208202803683370190505b5094508067ffffffffffffffff811115611c4d57611c4d612df1565b604051908082528060200260200182016040528015611c76578160200160208202803683370190505b5096508067ffffffffffffffff811115611c9257611c92612df1565b604051908082528060200260200182016040528015611cbb578160200160208202803683370190505b5095508067ffffffffffffffff811115611cd757611cd7612df1565b604051908082528060200260200182016040528015611d0a57816020015b6060815260200190600190039081611cf55790505b5093508067ffffffffffffffff811115611d2657611d26612df1565b604051908082528060200260200182016040528015611d4f578160200160208202803683370190505b5092505f5b81811015611f3d5760168181548110611d6f57611d6f613134565b905f5260205f200154868281518110611d8a57611d8a613134565b6020026020010181815250505f60155f888481518110611dac57611dac613134565b602002602001015181526020019081526020015f2090505f8490505f8260030154905081811115611ddb578091505b611de582426133aa565b8354600285018054604080516020808402820181019092528281529495505f94611e4f946001600160a01b03169390929091830182828015611e4457602002820191905f5260205f20905b815481526020019060010190808311611e30575b505050505084612962565b8a8781518110611e6157611e61613134565b602090810291909101015290508015611f0e5781600254611e829190613148565b8b8f81518110611e9457611e94613134565b6020026020010181815250508a8e81518110611eb257611eb2613134565b60200260200101518d611ec59190613121565b9c50898581518110611ed957611ed9613134565b60200260200101518c8f81518110611ef357611ef3613134565b6020908102919091010152611f078e6133bd565b9d50611f2e565b81888681518110611f2157611f21613134565b6020026020010181815250505b50505050806001019050611d54565b505b50509091929394959697565b601754604051633cebfa4f60e01b8152600481018590525f9182916001600160a01b0390911690633cebfa4f906024016040805180830381865afa158015611f95573d5f803e3d5ffd5b505050506040513d601f19601f82011682018060405250810190611fb991906134aa565b60185491935091506001600160a01b0380841691161461200357601854604051630b80380d60e31b81526001600160a01b0391821660048201529083166024820152604401610956565b6003546bffffffffffffffffffffffff821681111561204c57604051632b30b24760e21b81526bffffffffffffffffffffffff8316600482015260248101829052604401610956565b5f5b845181101561212b5760175485515f916001600160a01b0316906375c1f934908a9089908690811061208257612082613134565b60200260200101516040518363ffffffff1660e01b81526004016120b692919091825263ffffffff16602082015260400190565b602060405180830381865afa1580156120d1573d5f803e3d5ffd5b505050506040513d601f19601f820116820180604052508101906120f591906134dd565b90508281101561212257604051632b30b24760e21b81526004810182905260248101849052604401610956565b5060010161204e565b50505050505050565b600b546001600160a01b03161561215d5760405162dc149f60e41b815260040160405180910390fd5b8051158061216d57506020810151155b8061217a57506040810151155b80612187575060c0810151155b806121955750610100810151155b806121a2575060e0810151155b806121af57506080810151155b806121bc575060a0810151155b156121da57604051637c946ed760e01b815260040160405180910390fd5b8060a001518160800151101561221657608081015160a082015160405163491a2bb160e01b815260048101929092526024820152604401610956565b60028160600151101561224c57606081015160405163491a2bb160e01b8152600481019190915260026024820152604401610956565b6101a08101516001600160a01b0316158061227357506101c08101516001600160a01b0316155b156122915760405163d92e233d60e01b815260040160405180910390fd5b806101c001516001600160a01b03163b5f036122d2576101c081015160405163601c0c2160e01b81526001600160a01b039091166004820152602401610956565b80515f90815560208201516001556040820151600255606082015160035560a082015160045560c082015160055560e08201516006556101008201516007556101a0820151600b80546001600160a01b039283166001600160a01b0319918216179091556101c0840151600c8054919093169116179055610140820151600855610160820151600955805b8261012001515181101561242b5781836101200151828151811061238357612383613134565b6020026020010151116123cb5782610120015181815181106123a7576123a7613134565b6020026020010151604051632ab10b0b60e21b815260040161095691815260200190565b82610120015181815181106123e2576123e2613134565b602090810291909101015160148054600181810183555f929092527fce6d7b5282bd9a3661ae061feed1dbda4e52ab073b1f9285be6e155d9c38d4ec018290559092500161235d565b506101808201515f0361245157604051637c946ed760e01b815260040160405180910390fd5b610180820151600a55600554608083015161246c9190613148565b600d5560055460a08301516124819190613148565b600e5560e08201516020830151604084015161249d9190613148565b6124a79190613148565b601255505042601355565b5f6040516323b872dd60e01b5f5284600452836024528260445260205f60645f808a5af13d15601f3d1160015f511416171691505f60605280604052508061252f5760405163abae3d6d60e01b81526001600160a01b03808716600483015280861660248301528416604482015260648101839052608401610956565b5050505050565b82516060908267ffffffffffffffff81111561255457612554612df1565b60405190808252806020026020018201604052801561257d578160200160208202803683370190505b5091505f8367ffffffffffffffff81111561259a5761259a612df1565b6040519080825280602002602001820160405280156125c3578160200160208202803683370190505b5090505f8467ffffffffffffffff8111156125e0576125e0612df1565b604051908082528060200260200182016040528015612609578160200160208202803683370190505b5090505f8567ffffffffffffffff81111561262657612626612df1565b60405190808252806020026020018201604052801561264f578160200160208202803683370190505b5090505f8667ffffffffffffffff81111561266c5761266c612df1565b604051908082528060200260200182016040528015612695578160200160208202803683370190505b5090505f805f5b878110156127f1575f8c82815181106126b7576126b7613134565b602002602001015111156127e9578b81815181106126d7576126d7613134565b60200260200101519150818984815181106126f4576126f4613134565b6020908102919091018101919091525f838152601590915260409020600181015488516001600160a01b039091169089908690811061273557612735613134565b6001600160a01b0392831660209182029290920101528154885191169088908690811061276457612764613134565b60200260200101906001600160a01b031690816001600160a01b0316815250508b828151811061279657612796613134565b60200260200101518685815181106127b0576127b0613134565b602002602001018181525050818585815181106127cf576127cf613134565b6020908102919091010152836127e4816133bd565b945050505b60010161269c565b50885b801561289f5787612804816134f4565b98505f9050846128156001846133aa565b8151811061282557612825613134565b602002602001015190506016898154811061284257612842613134565b905f5260205f2001546016828154811061285e5761285e613134565b5f91825260209091200155601680548061287a5761287a613411565b600190038181905f5260205f20015f905590555080612898906134f4565b90506127f4565b50600f547fd19a3d42ed383465e4058c322d9411aeac76ddb8454d22e139fc99808bd56952898888886040516128d89493929190613541565b60405180910390a2505050505050509392505050565b8060105f8282546128ff91906133aa565b909155505060185461291b906001600160a01b03168383612b49565b816001600160a01b03167f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243648260405161295691815260200190565b60405180910390a25050565b6040516001600160a01b03841660248201525f90606090829060440160408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663d564c4bf60e01b179052600c5490519192505f9182916001600160a01b0316906129de908590613579565b5f60405180830381855afa9150503d805f8114612a16576040519150601f19603f3d011682016040523d82523d5f602084013e612a1b565b606091505b5091509150818015612a2e5750603f8151115b8015612a45575060208151612a43919061358f565b155b15612b3e5780806020019051810190612a5e9190613309565b9350838787604051602401612a75939291906135a2565b60408051601f198184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1663184023a560e01b179052600c5490519194506001600160a01b031690612ad1908590613579565b5f60405180830381855afa9150503d805f8114612b09576040519150601f19603f3d011682016040523d82523d5f602084013e612b0e565b606091505b509092509050818015612b22575080516020145b15612b3e5780806020019051810190612b3b91906135d7565b94505b505050935093915050565b5f60405163a9059cbb60e01b5f52836004528260245260205f60445f80895af13d15601f3d1160015f511416171691505f606052806040525080612bc05760405163abae3d6d60e01b81526001600160a01b0380861660048301523060248301528416604482015260648101839052608401610956565b50505050565b828054828255905f5260205f20908101928215612bff579160200282015b82811115612bff578251825591602001919060010190612be4565b50612c0b929150612c2d565b5090565b5080545f8255905f5260205f2090810190612c2a9190612c2d565b50565b5b80821115612c0b575f8155600101612c2e565b6001600160a01b0381168114612c2a575f80fd5b8035612c6081612c41565b919050565b5f805f805f60808688031215612c79575f80fd5b8535612c8481612c41565b94506020860135612c9481612c41565b935060408601359250606086013567ffffffffffffffff80821115612cb7575f80fd5b818801915088601f830112612cca575f80fd5b813581811115612cd8575f80fd5b896020828501011115612ce9575f80fd5b9699959850939650602001949392505050565b5f60208284031215612d0c575f80fd5b5035919050565b602080825282516001600160a01b0390811683830152838201511660408084019190915283015160c06060840152805160e084018190525f929182019083906101008601905b80831015612d795783518252928401926001929092019190840190612d59565b5060608701516080870152608087015160a087015260a087015160c08701528094505050505092915050565b5f815180845260208085019450602084015f5b83811015612dd457815187529582019590820190600101612db8565b509495945050505050565b602081525f61073c6020830184612da5565b634e487b7160e01b5f52604160045260245ffd5b6040516101e0810167ffffffffffffffff81118282101715612e2957612e29612df1565b60405290565b604051610100810167ffffffffffffffff81118282101715612e2957612e29612df1565b604051601f8201601f1916810167ffffffffffffffff81118282101715612e7c57612e7c612df1565b604052919050565b5f67ffffffffffffffff821115612e9d57612e9d612df1565b5060051b60200190565b5f82601f830112612eb6575f80fd5b81356020612ecb612ec683612e84565b612e53565b8083825260208201915060208460051b870101935086841115612eec575f80fd5b602086015b84811015612f085780358352918301918301612ef1565b509695505050505050565b5f805f60608486031215612f25575f80fd5b833567ffffffffffffffff80821115612f3c575f80fd5b908501906101e08288031215612f50575f80fd5b612f58612e05565b823581526020830135602082015260408301356040820152606083013560608201526080830135608082015260a083013560a082015260c083013560c082015260e083013560e08201526101008084013581830152506101208084013583811115612fc1575f80fd5b612fcd8a828701612ea7565b91830191909152506101408381013590820152610160808401359082015261018080840135908201526101a09150613006828401612c55565b828201526101c0915061301a828401612c55565b8282015280955050505061303060208501612c55565b915061303e60408501612c55565b90509250925092565b608081525f6130596080830187612da5565b828103602084015261306b8187612da5565b9050828103604084015261307f8186612da5565b905082810360608401526130938185612da5565b979650505050505050565b634e487b7160e01b5f52602160045260245ffd5b60208101600383106130d257634e487b7160e01b5f52602160045260245ffd5b91905290565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b634e487b7160e01b5f52601160045260245ffd5b808201808211156106405761064061310d565b634e487b7160e01b5f52603260045260245ffd5b80820281158282048414176106405761064061310d565b634e487b7160e01b5f52601260045260245ffd5b5f826131815761318161315f565b500490565b80516bffffffffffffffffffffffff81168114612c60575f80fd5b8051612c6081612c41565b805163ffffffff81168114612c60575f80fd5b805160068110612c60575f80fd5b5f82601f8301126131dc575f80fd5b815160206131ec612ec683612e84565b8083825260208201915060208460051b87010193508684111561320d575f80fd5b602086015b84811015612f0857613223816131ac565b8352918301918301613212565b5f60208284031215613240575f80fd5b815167ffffffffffffffff80821115613257575f80fd5b90830190610100828603121561326b575f80fd5b613273612e2f565b61327c83613186565b815261328a602084016131a1565b6020820152604083015160408201526132a5606084016131ac565b60608201526132b6608084016131ac565b60808201526132c760a084016131ac565b60a08201526132d860c084016131bf565b60c082015260e0830151828111156132ee575f80fd5b6132fa878286016131cd565b60e08301525095945050505050565b5f602080838503121561331a575f80fd5b825167ffffffffffffffff811115613330575f80fd5b8301601f81018513613340575f80fd5b805161334e612ec682612e84565b81815260059190911b8201830190838101908783111561336c575f80fd5b928401925b8284101561309357835182529284019290840190613371565b828152604060208201525f6133a26040830184612da5565b949350505050565b818103818111156106405761064061310d565b5f600182016133ce576133ce61310d565b5060010190565b848152608060208201525f6133ed6080830186612da5565b82810360408401526133ff8186612da5565b91505082606083015295945050505050565b634e487b7160e01b5f52603160045260245ffd5b848152608060208201525f61343d6080830186612da5565b6040830194909452506060015292915050565b5f60608201858352602060606020850152818654808452608086019150875f5260205f2093505f5b8181101561349457845483526001948501949284019201613478565b5050809350505050826040830152949350505050565b5f80604083850312156134bb575f80fd5b82516134c681612c41565b91506134d460208401613186565b90509250929050565b5f602082840312156134ed575f80fd5b5051919050565b5f816135025761350261310d565b505f190190565b5f815180845260208085019450602084015f5b83811015612dd45781516001600160a01b03168752958201959082019060010161351c565b608081525f6135536080830187612da5565b82810360208401526135658187613509565b9050828103604084015261307f8186613509565b5f82518060208501845e5f920191825250919050565b5f8261359d5761359d61315f565b500690565b606081525f6135b46060830186612da5565b82810360208401526135c68186612da5565b915050826040830152949350505050565b5f602082840312156135e7575f80fd5b8151801515811461073c575f80fdfea26469706673582212205776961a63fdaa13bebe3a0b2e71165c50721be211795e8926959409ae3d540364736f6c63430008190033", + "linkReferences": {}, + "deployedLinkReferences": {} +} \ No newline at end of file From f88c3543a42ea3f866a725bd51fbb801bf4acdfb Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 17:24:33 +0000 Subject: [PATCH 155/463] refactor: process killing, logging, var names for clarity --- electron/main.js | 81 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/electron/main.js b/electron/main.js index 763e4f984..7afb26cca 100644 --- a/electron/main.js +++ b/electron/main.js @@ -70,11 +70,19 @@ let splashWindow = null; /** @type {Electron.Tray | null} */ let tray = null; -let operateDaemon, operateDaemonPid, nextAppProcess, nextAppProcessPid; +// Used in production and development +let operateDaemon; +let operateDaemonPid; +// Child processes for running next app are only used in development +// required for hot reloads and other dev features +let devNextApp; +let devNextAppPid; + +// Next.js app instance for production // @ts-ignore - Workaround for the missing type definitions const nextApp = next({ - dev: false, // this instance is only used for production + dev: false, // DO NOT SET TO TRUE dir: path.join(__dirname), }); @@ -85,28 +93,73 @@ function showNotification(title, body) { } async function beforeQuit() { - if (operateDaemonPid) { + // destroy all ui components for immediate feedback + tray?.destroy(); + splashWindow?.destroy(); + mainWindow?.destroy(); + + if (operateDaemon || operateDaemonPid) { + // gracefully stop running services try { await fetch( `http://localhost:${appConfig.ports.prod.operate}/stop_all_services`, ); - await killProcesses(operateDaemonPid); } catch (e) { - logger.electron(e); + logger.electron("Couldn't stop_all_services gracefully:"); + logger.electron(JSON.stringify(e, null, 2)); + } + + // clean-up via pid first* + // may have dangling subprocesses + try { + operateDaemonPid && (await killProcesses(operateDaemonPid)); + } catch (e) { + logger.electron("Couldn't kill daemon processes via pid:"); + logger.electron(JSON.stringify(e, null, 2)); + } + + // attempt to kill the daemon process via kill + // if the pid-based cleanup fails + try { + const dead = operateDaemon?.kill(); + if (!dead) { + logger.electron('Daemon process still alive after kill'); + } + } catch (e) { + logger.electron("Couldn't kill operate daemon process via kill:"); + logger.electron(JSON.stringify(e, null, 2)); } } - if (nextAppProcessPid) { + if (devNextApp || devNextAppPid) { + // attempt graceful kill first with next app + try { + const dead = devNextApp?.kill(); + if (!dead) { + logger.electron('Dev NextApp process still alive after kill'); + } + } catch (e) { + logger.electron("Couldn't kill devNextApp process via kill:"); + logger.electron(JSON.stringify(e, null, 2)); + } + + // attempt to kill the dev next app process via pid try { - await killProcesses(nextAppProcessPid); + devNextAppPid && (await killProcesses(devNextAppPid)); } catch (e) { - logger.electron(e); + logger.electron("Couldn't kill devNextApp processes via pid:"); + logger.electron(JSON.stringify(e, null, 2)); } } - tray?.destroy(); - splashWindow?.destroy(); - mainWindow?.destroy(); + if (nextApp) { + // attempt graceful close of prod next app + await nextApp.close().catch((e) => { + logger.electron("Couldn't close NextApp gracefully:"); + logger.electron(JSON.stringify(e, null, 2)); + }); + // electron will kill next service on exit + } } const APP_WIDTH = 460; @@ -340,7 +393,7 @@ async function launchNextApp() { async function launchNextAppDev() { await new Promise(function (resolve, _reject) { process.env.NEXT_PUBLIC_BACKEND_PORT = appConfig.ports.dev.operate; // must set next env var to connect to backend - nextAppProcess = spawn( + devNextApp = spawn( 'yarn', ['dev:frontend', '--port', appConfig.ports.dev.next], { @@ -352,8 +405,8 @@ async function launchNextAppDev() { }, }, ); - nextAppProcessPid = nextAppProcess.pid; - nextAppProcess.stdout.on('data', (data) => { + devNextAppPid = devNextApp.pid; + devNextApp.stdout.on('data', (data) => { logger.next(data.toString().trim()); resolve(); }); From 7f3ef6286946872bbc3437bbf8b789c3f64f4a3e Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 17:25:05 +0000 Subject: [PATCH 156/463] feat: add electron logging to killProcesses --- electron/processes.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/electron/processes.js b/electron/processes.js index faaa9266f..e65e2ed23 100644 --- a/electron/processes.js +++ b/electron/processes.js @@ -16,15 +16,16 @@ function killProcesses(pid) { // Array of PIDs to kill, starting with the children const pidsToKill = children.map((p) => p.PID); - logger.info("Pids to kill " + JSON.stringify(pidsToKill)); + logger.electron('Pids to kill ' + JSON.stringify(pidsToKill)); const killCommand = isWindows ? windowsKillCommand : unixKillCommand; let errors = []; - for (const ppid of pidsToKill) { - logger.info("kill: " + ppid); - exec(`${killCommand} ${ppid}`, (err) => { - logger.error("Pids to kill error:" + err); + for (const pid of pidsToKill) { + logger.electron('killing: ' + pid); + exec(`${killCommand} ${pid}`, (err) => { + logger.electron(`error killing pid ${pid}`); + logger.electron(JSON.stringify(err, null, 2)); if ( err?.message?.includes(isWindows ? 'not found' : 'No such process') ) { @@ -36,9 +37,7 @@ function killProcesses(pid) { if (errors.length === 0) { reject(errors); - - - } else resolve(); + } else resolve(); }); }); } From 62b1f5da66a487ddcfb86cd603068c3929d7f543 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 18:29:53 +0100 Subject: [PATCH 157/463] doc: api.md --- api.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api.md b/api.md index 675dc9896..145e450bb 100644 --- a/api.md +++ b/api.md @@ -196,7 +196,7 @@ Creates a master key for given chain type. "address": "0xAafd5cb31a611C5e5aa65ea8c6226EB4328175E1", "safe_chains": [], "ledger_type": 0, - "safe": null, + "safes": {}, "safe_nonce": null }, "mnemonic": [...] @@ -205,7 +205,7 @@ Creates a master key for given chain type. --- -#### `PUT /api/wallet` +#### `POST /api/wallet/safe` Creates a gnosis safe for given chain type. @@ -230,7 +230,9 @@ Creates a gnosis safe for given chain type. 2 ], "ledger_type": 0, - "safe": "0xe56fb574ce2C66008d5c4C09980c4f36Ab81ff22", + "safes": { + "2": "0xe56fb574ce2C66008d5c4C09980c4f36Ab81ff22" + }, "safe_nonce": 110558881674480320952254000342160989674913430251157716140571305138121962898821 } ``` From 119b6985b7667ad206b9077aa5e1da0490f21625 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:38:23 +0000 Subject: [PATCH 158/463] enforce err --- electron/processes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/electron/processes.js b/electron/processes.js index e65e2ed23..5a1e8ba0f 100644 --- a/electron/processes.js +++ b/electron/processes.js @@ -24,8 +24,8 @@ function killProcesses(pid) { for (const pid of pidsToKill) { logger.electron('killing: ' + pid); exec(`${killCommand} ${pid}`, (err) => { - logger.electron(`error killing pid ${pid}`); - logger.electron(JSON.stringify(err, null, 2)); + err && logger.electron(`error killing pid ${pid}`); + err && logger.electron(JSON.stringify(err, null, 2)); if ( err?.message?.includes(isWindows ? 'not found' : 'No such process') ) { From 3de2a136f666287f79b2ee308b468d38f1b8cd92 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 12 Nov 2024 17:40:26 +0000 Subject: [PATCH 159/463] bump: rc196 --- package.json | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 517578861..16dbf2dd6 100644 --- a/package.json +++ b/package.json @@ -63,5 +63,5 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc195" + "version": "0.1.0-rc196" } \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 8d66f2f07..440429ad3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc195" +version = "0.1.0-rc196" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md" From a845e62dc882fb3a8598485500ace00c96428ecb Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Tue, 12 Nov 2024 17:44:37 +0000 Subject: [PATCH 160/463] Update electron/main.js --- electron/main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/electron/main.js b/electron/main.js index 7afb26cca..6c453b6af 100644 --- a/electron/main.js +++ b/electron/main.js @@ -80,6 +80,7 @@ let devNextApp; let devNextAppPid; // Next.js app instance for production +// requires http server wrap to work; assign port, receive requests, deliver responses // @ts-ignore - Workaround for the missing type definitions const nextApp = next({ dev: false, // DO NOT SET TO TRUE From ccfbde729926d7ad52a1218427f94b472d07227c Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 19:19:40 +0100 Subject: [PATCH 161/463] chore: refactor env_variables -> service_env_variables --- frontend/client/types.ts | 2 +- frontend/constants/serviceTemplates.ts | 2 +- operate/operate_types.py | 2 +- operate/services/service.py | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index e7cd26cdd..1f41f9c9f 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -68,7 +68,7 @@ export type ServiceTemplate = { service_version: string; home_chain_id: string; configurations: { [key: string]: ConfigurationTemplate }; - env_variables: { [key: string]: ServiceEnvVariable }; + service_env_variables: { [key: string]: ServiceEnvVariable }; deploy?: boolean; }; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 1ce979f6b..6696eda6a 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -29,7 +29,7 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ }, }, }, - env_variables: {}, // TODO: add env variables + service_env_variables: {}, // TODO: add env variables }, // { // name: 'Optimus Test', diff --git a/operate/operate_types.py b/operate/operate_types.py index bd64032be..191666628 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -235,7 +235,7 @@ class ServiceTemplate(TypedDict): service_version: str home_chain_id: str configurations: ConfigurationTemplates - env_variables: ServiceEnvVariables + service_env_variables: ServiceEnvVariables @dataclass diff --git a/operate/services/service.py b/operate/services/service.py index 2e2793e10..567845dc8 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -656,7 +656,7 @@ class Service(LocalResource): home_chain_id: str chain_configs: ChainConfigs description: str - env_variables: ServiceEnvVariables + service_env_variables: ServiceEnvVariables path: Path service_path: Path @@ -780,7 +780,7 @@ def migrate_format(cls, path: Path) -> bool: def consume_env_variables(self) -> None: """Consume environment variables.""" - for variable in self.env_variables.values(): + for variable in self.service_env_variables.values(): os.environ[variable["env_variable_name"]] = str(variable["value"]) @classmethod @@ -858,7 +858,7 @@ def new( # pylint: disable=too-many-locals chain_configs=chain_configs, path=service_path.parent, service_path=service_path, - env_variables=service_template["service_env_variables"], + service_env_variables=service_template["service_env_variables"], ) service.store() return service From f32cbbe9c95b453d8cd2fe47f450f776159f3d0f Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 19:41:27 +0100 Subject: [PATCH 162/463] chore: add env variables --- frontend/client/enums.ts | 6 ++ frontend/client/types.ts | 4 +- frontend/constants/serviceTemplates.ts | 82 +++++++++++++++++++++++++- 3 files changed, 87 insertions(+), 5 deletions(-) diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index f880c942d..08bc12a5a 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -36,3 +36,9 @@ export enum AccountIsSetup { Loading, Error, } + +export enum EnvProvisionType { + FIXED = "fixed", + USER = "user", + COMPUTED = "computed" +} \ No newline at end of file diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 1f41f9c9f..b8a507bca 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -1,7 +1,7 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; -import { DeploymentStatus, Ledger, MiddlewareChain } from './enums'; +import { DeploymentStatus, Ledger, MiddlewareChain, EnvProvisionType } from './enums'; export type ServiceHash = string; @@ -50,8 +50,6 @@ export type Service = { }; -export type EnvProvisionType = "fixed" | "user" | "computed"; - export type ServiceEnvVariable = { name: string; env_variable_name: string; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 6696eda6a..b7a5702a8 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -1,4 +1,4 @@ -import { ServiceTemplate } from '@/client'; +import { ServiceTemplate, EnvProvisionType } from '@/client'; import { StakingProgramId } from '@/enums/StakingProgram'; import { CHAINS } from './chains'; @@ -29,7 +29,85 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ }, }, }, - service_env_variables: {}, // TODO: add env variables + service_env_variables: { + GNOSIS_LEDGER_RPC: { + name: "Gnosis ledger RPC", + env_variable_name: "GNOSIS_LEDGER_RPC", + description: "", + value: "", + provision_type: EnvProvisionType.COMPUTED + }, + // ETHEREUM_LEDGER_RPC: { + // name: "Ethereum ledger RPC", + // env_variable_name: "ETHEREUM_LEDGER_RPC", + // description: "", + // value: "", + // provision_type: EnvProvisionType.COMPUTED + // }, + // BASE_LEDGER_RPC: { + // name: "Base ledger RPC", + // env_variable_name: "BASE_LEDGER_RPC", + // description: "", + // value: "", + // provision_type: EnvProvisionType.COMPUTED + // }, + // OPTIMISM_LEDGER_RPC: { + // name: "Optimism ledger RPC", + // env_variable_name: "OPTIMISM_LEDGER_RPC", + // description: "", + // value: "", + // provision_type: EnvProvisionType.COMPUTED + // }, + STAKING_CONTRACT_ADDRESS: { + name: "Staking contract address", + env_variable_name: "STAKING_CONTRACT_ADDRESS", + description: "", + value: "", + provision_type: EnvProvisionType.COMPUTED + }, + MECH_ACTIVITY_CHECKER_CONTRACT: { + name: "Mech activity checker contract", + env_variable_name: "MECH_ACTIVITY_CHECKER_CONTRACT", + description: "", + value: "", + provision_type: EnvProvisionType.COMPUTED + }, + MECH_CONTRACT_ADDRESS: { + name: "Mech contract address", + env_variable_name: "MECH_CONTRACT_ADDRESS", + description: "", + value: "", + provision_type: EnvProvisionType.COMPUTED + }, + MECH_REQUEST_PRICE: { + name: "Mech request price", + env_variable_name: "MECH_REQUEST_PRICE", + description: "", + value: "", + provision_type: EnvProvisionType.COMPUTED + }, + USE_MECH_MARKETPLACE: { + name: "Use Mech marketplace", + env_variable_name: "USE_MECH_MARKETPLACE", + description: "", + value: "", + provision_type: EnvProvisionType.COMPUTED + }, + REQUESTER_STAKING_INSTANCE_ADDRESS: { + name: "Requester staking instance address", + env_variable_name: "REQUESTER_STAKING_INSTANCE_ADDRESS", + description: "", + value: "", + provision_type: EnvProvisionType.COMPUTED + }, + PRIORITY_MECH_ADDRESS: { + name: "Priority Mech address", + env_variable_name: "PRIORITY_MECH_ADDRESS", + description: "", + value: "", + provision_type: EnvProvisionType.COMPUTED + } + }, }, // { // name: 'Optimus Test', From cda8c1473845869a8893991000dde1dc3a21041e Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 23:00:22 +0100 Subject: [PATCH 163/463] feat: compute env vars --- frontend/client/types.ts | 6 ++- frontend/constants/serviceTemplates.ts | 2 +- operate/operate_types.py | 4 +- operate/services/manage.py | 68 +++++++++++++++++++------- operate/services/service.py | 8 +-- operate/wallet/master.py | 11 +++-- 6 files changed, 68 insertions(+), 31 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index b8a507bca..e7cd26cdd 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -1,7 +1,7 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; -import { DeploymentStatus, Ledger, MiddlewareChain, EnvProvisionType } from './enums'; +import { DeploymentStatus, Ledger, MiddlewareChain } from './enums'; export type ServiceHash = string; @@ -50,6 +50,8 @@ export type Service = { }; +export type EnvProvisionType = "fixed" | "user" | "computed"; + export type ServiceEnvVariable = { name: string; env_variable_name: string; @@ -66,7 +68,7 @@ export type ServiceTemplate = { service_version: string; home_chain_id: string; configurations: { [key: string]: ConfigurationTemplate }; - service_env_variables: { [key: string]: ServiceEnvVariable }; + env_variables: { [key: string]: ServiceEnvVariable }; deploy?: boolean; }; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index b7a5702a8..10016d4af 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -29,7 +29,7 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ }, }, }, - service_env_variables: { + env_variables: { GNOSIS_LEDGER_RPC: { name: "Gnosis ledger RPC", env_variable_name: "GNOSIS_LEDGER_RPC", diff --git a/operate/operate_types.py b/operate/operate_types.py index 191666628..023401f88 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -203,7 +203,7 @@ class ConfigurationTemplate(TypedDict): fallback_chain_params: t.Optional[t.Dict] -class ServiceEnvProvisionType(enum.Enum): +class ServiceEnvProvisionType(str, enum.Enum): """Service environment variable provision type.""" FIXED = "fixed" @@ -235,7 +235,7 @@ class ServiceTemplate(TypedDict): service_version: str home_chain_id: str configurations: ConfigurationTemplates - service_env_variables: ServiceEnvVariables + env_variables: ServiceEnvVariables @dataclass diff --git a/operate/services/manage.py b/operate/services/manage.py index 8b1d7b13a..6ed0ef62c 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -38,7 +38,12 @@ from operate.keys import Key, KeysManager from operate.ledger import PUBLIC_RPCS from operate.ledger.profiles import CONTRACTS, OLAS, STAKING -from operate.operate_types import ChainType, LedgerConfig, ServiceTemplate +from operate.operate_types import ( + ChainType, + LedgerConfig, + ServiceEnvProvisionType, + ServiceTemplate, +) from operate.services.protocol import EthSafeTxBuilder, OnChainManager, StakingState from operate.services.service import ( ChainConfig, @@ -232,6 +237,45 @@ def create( return service + def _compute_service_variables( + self, service: Service, staking_params: t.Dict[str, str] + ) -> None: + """Compute values to override service.yaml variables for the deployment.""" + + # TODO A customized, arbitrary computation mechanism should be devised. + computed_values = { + "ETHEREUM_LEDGER_RPC": PUBLIC_RPCS[ChainType.ETHEREUM], + "GNOSIS_LEDGER_RPC": PUBLIC_RPCS[ChainType.GNOSIS], + "BASE_LEDGER_RPC": PUBLIC_RPCS[ChainType.BASE], + "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[ChainType.OPTIMISM], + "STAKING_CONTRACT_ADDRESS": staking_params.get("staking_contract"), + "MECH_ACTIVITY_CHECKER_CONTRACT": staking_params.get("activity_checker"), + "MECH_CONTRACT_ADDRESS": staking_params.get("agent_mech"), + "MECH_REQUEST_PRICE": "10000000000000000", + "USE_MECH_MARKETPLACE": "mech_marketplace" + in service.chain_configs[ + service.home_chain_id + ].chain_data.user_params.staking_program_id, + "REQUESTER_STAKING_INSTANCE_ADDRESS": staking_params.get( + "staking_contract" + ), + "PRIORITY_MECH_ADDRESS": staking_params.get("agent_mech"), + } + + updated = False + for var in service.env_variables.values(): + env_variable_name = var["env_variable_name"] + if ( + env_variable_name in computed_values + and var["provision_type"] == ServiceEnvProvisionType.COMPUTED + and var["value"] != computed_values.get(env_variable_name) + ): + var["value"] = str(computed_values.get(env_variable_name)) + updated = True + + if updated: + service.store() + 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 @@ -531,23 +575,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to agent_mech="0x77af31De935740567Cf4fF1986D04B2c964A786a", # nosec ) - # Override service.yaml variables for the deployment - os.environ["STAKING_CONTRACT_ADDRESS"] = staking_params["staking_contract"] - os.environ["MECH_ACTIVITY_CHECKER_CONTRACT"] = staking_params[ - "activity_checker" - ] - os.environ["MECH_CONTRACT_ADDRESS"] = staking_params["agent_mech"] - os.environ["MECH_REQUEST_PRICE"] = "10000000000000000" - os.environ["USE_MECH_MARKETPLACE"] = str( - chain_data.user_params.use_mech_marketplace - ) - os.environ["REQUESTER_STAKING_INSTANCE_ADDRESS"] = staking_params[ - "staking_contract" - ] - os.environ["PRIORITY_MECH_ADDRESS"] = staking_params["agent_mech"] - os.environ["ETHEREUM_LEDGER_RPC"] = PUBLIC_RPCS[ChainType.ETHEREUM] - os.environ["BASE_LEDGER_RPC"] = PUBLIC_RPCS[ChainType.BASE] - os.environ["OPTIMISM_LEDGER_RPC"] = PUBLIC_RPCS[ChainType.OPTIMISM] + self._compute_service_variables(service, staking_params) if user_params.use_staking: self.logger.info("Checking staking compatibility") @@ -1572,7 +1600,9 @@ def update_all_matching( def migrate_service_configs(self) -> None: """Migrate old service config formats to new ones, if applies.""" - bafybei_count = sum(1 for path in self.path.iterdir() if path.name.startswith("bafybei")) + bafybei_count = sum( + 1 for path in self.path.iterdir() if path.name.startswith("bafybei") + ) if bafybei_count > 1: self.log_directories() # raise RuntimeError(f"Your services folder contains {bafybei_count} folders starting with 'bafybei'. This is an unintended situation. Please contact support.") diff --git a/operate/services/service.py b/operate/services/service.py index 567845dc8..c226ec24a 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -656,7 +656,7 @@ class Service(LocalResource): home_chain_id: str chain_configs: ChainConfigs description: str - service_env_variables: ServiceEnvVariables + env_variables: ServiceEnvVariables path: Path service_path: Path @@ -761,7 +761,7 @@ def migrate_format(cls, path: Path) -> bool: service_path = Path(data["service_path"]) if service_path.exists() and service_path.is_dir(): shutil.rmtree(service_path) - + path = path.rename(new_path) service_path = Path( IPFSTool().download( @@ -780,7 +780,7 @@ def migrate_format(cls, path: Path) -> bool: def consume_env_variables(self) -> None: """Consume environment variables.""" - for variable in self.service_env_variables.values(): + for variable in self.env_variables.values(): os.environ[variable["env_variable_name"]] = str(variable["value"]) @classmethod @@ -858,7 +858,7 @@ def new( # pylint: disable=too-many-locals chain_configs=chain_configs, path=service_path.parent, service_path=service_path, - service_env_variables=service_template["service_env_variables"], + env_variables=service_template["env_variables"], ) service.store() return service diff --git a/operate/wallet/master.py b/operate/wallet/master.py index f19d3f560..e3ec758ef 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -20,9 +20,9 @@ """Master key implementation""" import json +import logging import os import typing as t -import logging from dataclasses import dataclass, field from pathlib import Path @@ -426,7 +426,7 @@ def add_or_swap_owner( def load(cls, path: Path) -> "EthereumMasterWallet": """Load master wallet.""" # TODO: This is a complex way to read the 'safes' dictionary. - # The reason for that is that wallet.safes[chain_type] would fail + # The reason for that is that wallet.safes[chain_type] would fail # (for example in service manager) when passed a ChainType key. raw_ethereum_wallet = super().load(path) # type: ignore @@ -467,7 +467,12 @@ def migrate_format(cls, path: Path) -> bool: class MasterWalletManager: """Master wallet manager.""" - def __init__(self, path: Path, password: t.Optional[str] = None, logger: t.Optional[logging.Logger] = None) -> None: + def __init__( + self, + path: Path, + password: t.Optional[str] = None, + logger: t.Optional[logging.Logger] = None, + ) -> None: """Initialize master wallet manager.""" self.path = path self._password = password From fd3b92de9aac4dfc27ded1d9ef6ff0400ecede20 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 23:27:30 +0100 Subject: [PATCH 164/463] chore: refactor name --- operate/services/manage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 6ed0ef62c..147b0ee9a 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -237,7 +237,7 @@ def create( return service - def _compute_service_variables( + def _compute_service_env_variables( self, service: Service, staking_params: t.Dict[str, str] ) -> None: """Compute values to override service.yaml variables for the deployment.""" @@ -575,7 +575,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to agent_mech="0x77af31De935740567Cf4fF1986D04B2c964A786a", # nosec ) - self._compute_service_variables(service, staking_params) + self._compute_service_env_variables(service, staking_params) if user_params.use_staking: self.logger.info("Checking staking compatibility") From 77a2f6c41466817b2114edb1718ceadfb5bc92f7 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Tue, 12 Nov 2024 23:31:37 +0100 Subject: [PATCH 165/463] fix: missing method --- operate/services/service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/operate/services/service.py b/operate/services/service.py index c226ec24a..6c2565cde 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -428,6 +428,7 @@ def _build_docker( encoding="utf-8", ) try: + service.consume_env_variables() builder = ServiceBuilder.from_dir( path=service.service_path, keys_file=keys_file, From af620d18ffe48bfdd8d69128101411748859f9c1 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 00:21:09 +0000 Subject: [PATCH 166/463] chore: rename balance of fragment --- frontend/abis/erc20.ts | 2 +- frontend/components/MainPage/sections/AddFundsSection.tsx | 6 +++--- frontend/service/Multicall.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/abis/erc20.ts b/frontend/abis/erc20.ts index aafcd7086..2c32e58c0 100644 --- a/frontend/abis/erc20.ts +++ b/frontend/abis/erc20.ts @@ -1,5 +1,5 @@ import { Abi } from '@/types/Abi'; -export const ERC20_BALANCEOF_STRING_FRAGMENT: Abi = [ +export const ERC20_BALANCE_OF_STRING_FRAGMENT: Abi = [ 'function balanceOf(address owner) view returns (uint256)', ]; diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index bd37ea48e..444546228 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -17,7 +17,7 @@ import { forwardRef, useCallback, useMemo, useRef, useState } from 'react'; import styled from 'styled-components'; import { useInterval } from 'usehooks-ts'; -import { ERC20_BALANCEOF_STRING_FRAGMENT } from '@/abis/erc20'; +import { ERC20_BALANCE_OF_STRING_FRAGMENT } from '@/abis/erc20'; import { CHAIN_CONFIG } from '@/config/chains'; import { TOKEN_CONFIG } from '@/config/tokens'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; @@ -111,7 +111,7 @@ export const OpenAddFundsSection = forwardRef((_, ref) => { //USDC balance new Contract( TOKEN_CONFIG[CHAIN_CONFIG.ETHEREUM.chainId]['USDC'].address, - ERC20_BALANCEOF_STRING_FRAGMENT, + ERC20_BALANCE_OF_STRING_FRAGMENT, ETHEREUM_PROVIDER, ) .balanceOf(masterSafeAddress) @@ -124,7 +124,7 @@ export const OpenAddFundsSection = forwardRef((_, ref) => { .then(setopEth), new Contract( TOKEN_CONFIG[CHAIN_CONFIG.OPTIMISM.chainId]['OLAS'].address, - ERC20_BALANCEOF_STRING_FRAGMENT, + ERC20_BALANCE_OF_STRING_FRAGMENT, OPTIMISM_PROVIDER, ) .balanceOf(masterSafeAddress) diff --git a/frontend/service/Multicall.ts b/frontend/service/Multicall.ts index 6ba2f64c3..668247f9d 100644 --- a/frontend/service/Multicall.ts +++ b/frontend/service/Multicall.ts @@ -1,7 +1,7 @@ import { ethers } from 'ethers'; import { Contract as MulticallContract, ContractCall } from 'ethers-multicall'; -import { ERC20_BALANCEOF_STRING_FRAGMENT } from '@/abis/erc20'; +import { ERC20_BALANCE_OF_STRING_FRAGMENT } from '@/abis/erc20'; import { Erc20TokenConfig } from '@/config/tokens'; import { PROVIDERS } from '@/constants/providers'; import { ChainId } from '@/enums/Chain'; @@ -59,7 +59,7 @@ const getErc20Balances = async ( const callData: ContractCall[] = addresses.map((address: Address) => new MulticallContract( erc20TokenConfig.address, - ERC20_BALANCEOF_STRING_FRAGMENT, + ERC20_BALANCE_OF_STRING_FRAGMENT, ) .balanceOf(address) .then((balance: bigint) => From 6240763eb6973242fed7becdcaf34add44b87cb0 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 00:22:35 +0000 Subject: [PATCH 167/463] chore: extend commented hide top bar --- frontend/components/MainPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index dc196cfa4..c425294b4 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -36,7 +36,7 @@ export const Main = () => { // const hideMainOlasBalanceTopBorder = [ // !backupSafeAddress, - // currentStakingProgram === StakingProgramId.Alpha, + // currentStakingProgram === StakingProgramId.PearlAlpha, // ].some((condition) => !!condition); return ( From 03884f467cced2cc46e4eac1297fab6614b70793 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 10:08:52 +0100 Subject: [PATCH 168/463] fix: remove chain id from healthchecker --- operate/services/health_checker.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/operate/services/health_checker.py b/operate/services/health_checker.py index b3570a363..a6f709724 100644 --- a/operate/services/health_checker.py +++ b/operate/services/health_checker.py @@ -174,11 +174,7 @@ def _do_restart() -> None: service_manager.stop_service_locally( service_config_id=service_config_id ) - # TODO Optimus patch, chain_id="10" - chain_id = "10" - service_manager.deploy_service_locally( - service_config_id=service_config_id, chain_id=chain_id - ) + service_manager.deploy_service_locally(service_config_id=service_config_id) loop = asyncio.get_event_loop() with ThreadPoolExecutor() as executor: From 3a6c155369defb2fa2983d9cadc9df568642c86d Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Wed, 13 Nov 2024 10:14:53 +0000 Subject: [PATCH 169/463] Update frontend/components/MainPage/header/AgentButton/AgentButton.tsx Co-authored-by: Mohan --- frontend/components/MainPage/header/AgentButton/AgentButton.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx index 11b3a4cf9..d5cf98f2d 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx @@ -17,13 +17,11 @@ import { AgentStoppingButton } from './AgentStoppingButton'; export const AgentButton = () => { const { selectedService } = useServices(); - const { service, deploymentStatus: serviceStatus, isLoaded, } = useService({ serviceConfigId: selectedService?.service_config_id }); - const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo(); return useMemo(() => { From d52558d9c3b5c192c656c6ec288284ed40e3b350 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Wed, 13 Nov 2024 10:33:13 +0000 Subject: [PATCH 170/463] Update frontend/utils/numberFormatters.ts Co-authored-by: Mohan --- frontend/utils/numberFormatters.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/utils/numberFormatters.ts b/frontend/utils/numberFormatters.ts index ceb28dd98..88411c851 100644 --- a/frontend/utils/numberFormatters.ts +++ b/frontend/utils/numberFormatters.ts @@ -32,7 +32,7 @@ export const formatEther = (wei: BigNumberish): string => { }; /** - * Parse converts small numbers into larger numbers + * Converts small numbers into larger numbers * @note **multiplies** the input by `10 ** decimals` * @example parseUnits('1.0', 18) => '1000000000000000000' */ From b13dd1e5fd6dca4d14550b93e3ab68594965ee10 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 12:26:15 +0100 Subject: [PATCH 171/463] chore: refactor to dictionary-based approach --- frontend/client/types.ts | 5 ++--- frontend/constants/serviceTemplates.ts | 11 ----------- operate/operate_types.py | 7 +++---- operate/services/manage.py | 11 +++++------ operate/services/service.py | 8 ++++---- 5 files changed, 14 insertions(+), 28 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index e7cd26cdd..5a9101b14 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -52,9 +52,8 @@ export type Service = { export type EnvProvisionType = "fixed" | "user" | "computed"; -export type ServiceEnvVariable = { +export type EnvVariableAttributes = { name: string; - env_variable_name: string; description: string; value: string; provision_type: EnvProvisionType; @@ -68,7 +67,7 @@ export type ServiceTemplate = { service_version: string; home_chain_id: string; configurations: { [key: string]: ConfigurationTemplate }; - env_variables: { [key: string]: ServiceEnvVariable }; + env_variables: { [key: string]: EnvVariableAttributes }; deploy?: boolean; }; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 10016d4af..eabaf05a7 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -32,77 +32,66 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ env_variables: { GNOSIS_LEDGER_RPC: { name: "Gnosis ledger RPC", - env_variable_name: "GNOSIS_LEDGER_RPC", description: "", value: "", provision_type: EnvProvisionType.COMPUTED }, // ETHEREUM_LEDGER_RPC: { // name: "Ethereum ledger RPC", - // env_variable_name: "ETHEREUM_LEDGER_RPC", // description: "", // value: "", // provision_type: EnvProvisionType.COMPUTED // }, // BASE_LEDGER_RPC: { // name: "Base ledger RPC", - // env_variable_name: "BASE_LEDGER_RPC", // description: "", // value: "", // provision_type: EnvProvisionType.COMPUTED // }, // OPTIMISM_LEDGER_RPC: { // name: "Optimism ledger RPC", - // env_variable_name: "OPTIMISM_LEDGER_RPC", // description: "", // value: "", // provision_type: EnvProvisionType.COMPUTED // }, STAKING_CONTRACT_ADDRESS: { name: "Staking contract address", - env_variable_name: "STAKING_CONTRACT_ADDRESS", description: "", value: "", provision_type: EnvProvisionType.COMPUTED }, MECH_ACTIVITY_CHECKER_CONTRACT: { name: "Mech activity checker contract", - env_variable_name: "MECH_ACTIVITY_CHECKER_CONTRACT", description: "", value: "", provision_type: EnvProvisionType.COMPUTED }, MECH_CONTRACT_ADDRESS: { name: "Mech contract address", - env_variable_name: "MECH_CONTRACT_ADDRESS", description: "", value: "", provision_type: EnvProvisionType.COMPUTED }, MECH_REQUEST_PRICE: { name: "Mech request price", - env_variable_name: "MECH_REQUEST_PRICE", description: "", value: "", provision_type: EnvProvisionType.COMPUTED }, USE_MECH_MARKETPLACE: { name: "Use Mech marketplace", - env_variable_name: "USE_MECH_MARKETPLACE", description: "", value: "", provision_type: EnvProvisionType.COMPUTED }, REQUESTER_STAKING_INSTANCE_ADDRESS: { name: "Requester staking instance address", - env_variable_name: "REQUESTER_STAKING_INSTANCE_ADDRESS", description: "", value: "", provision_type: EnvProvisionType.COMPUTED }, PRIORITY_MECH_ADDRESS: { name: "Priority Mech address", - env_variable_name: "PRIORITY_MECH_ADDRESS", description: "", value: "", provision_type: EnvProvisionType.COMPUTED diff --git a/operate/operate_types.py b/operate/operate_types.py index 023401f88..36482a0e7 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -211,18 +211,17 @@ class ServiceEnvProvisionType(str, enum.Enum): COMPUTED = "computed" -class ServiceEnvVariable(TypedDict): +class EnvVariableAttributes(TypedDict): """Service environment variable template.""" name: str - env_variable_name: str description: str value: str provision_type: ServiceEnvProvisionType ConfigurationTemplates = t.Dict[str, ConfigurationTemplate] -ServiceEnvVariables = t.Dict[str, ServiceEnvVariable] +EnvVariables = t.Dict[str, EnvVariableAttributes] class ServiceTemplate(TypedDict): @@ -235,7 +234,7 @@ class ServiceTemplate(TypedDict): service_version: str home_chain_id: str configurations: ConfigurationTemplates - env_variables: ServiceEnvVariables + env_variables: EnvVariables @dataclass diff --git a/operate/services/manage.py b/operate/services/manage.py index 147b0ee9a..1803c1f89 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -263,14 +263,13 @@ def _compute_service_env_variables( } updated = False - for var in service.env_variables.values(): - env_variable_name = var["env_variable_name"] + for env_var, attributes in service.env_variables.items(): if ( - env_variable_name in computed_values - and var["provision_type"] == ServiceEnvProvisionType.COMPUTED - and var["value"] != computed_values.get(env_variable_name) + env_var in computed_values + and attributes["provision_type"] == ServiceEnvProvisionType.COMPUTED + and attributes["value"] != computed_values.get(env_var) ): - var["value"] = str(computed_values.get(env_variable_name)) + attributes["value"] = str(computed_values.get(env_var)) updated = True if updated: diff --git a/operate/services/service.py b/operate/services/service.py index 6c2565cde..c6302ad81 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -82,7 +82,7 @@ OnChainData, OnChainState, OnChainUserParams, - ServiceEnvVariables, + EnvVariables, ServiceTemplate, ) from operate.resource import LocalResource @@ -657,7 +657,7 @@ class Service(LocalResource): home_chain_id: str chain_configs: ChainConfigs description: str - env_variables: ServiceEnvVariables + env_variables: EnvVariables path: Path service_path: Path @@ -781,8 +781,8 @@ def migrate_format(cls, path: Path) -> bool: def consume_env_variables(self) -> None: """Consume environment variables.""" - for variable in self.env_variables.values(): - os.environ[variable["env_variable_name"]] = str(variable["value"]) + for env_var, attributes in self.env_variables.items(): + os.environ[env_var] = str(attributes["value"]) @classmethod def load(cls, path: Path) -> "Service": From bb4c251bb3bd239a043c19ab7c10259ee22506e9 Mon Sep 17 00:00:00 2001 From: Mohan Date: Wed, 13 Nov 2024 17:36:40 +0530 Subject: [PATCH 172/463] feat: integrate v2 API endpoints (#440) * feat: add BACKEND_URL_V2 for versioned API endpoint * feat: implement support for versioned API and chain-specific service configurations * chore: remove commented-out deployment methods from Services.ts * feat: update service fetch URLs to use BACKEND_URL_V2 for consistency * feat: refactor service handling to use service_config_id instead of hash * feat: update types for MiddlewareServiceResponse and ServiceTemplate to include new fields and improve structure * refactor: remove unused types and update service_config_id references in ServiceTemplate * Update frontend/constants/serviceTemplates.ts Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> --------- Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> --- frontend/client/types.ts | 69 +++---- .../MainPage/header/AgentButton.tsx | 6 +- .../StakingContractSection/MigrateButton.tsx | 11 +- frontend/constants/urls.ts | 2 + frontend/context/ServicesProvider.tsx | 8 +- frontend/hooks/useServiceTemplates.ts | 8 +- frontend/hooks/useServices.ts | 9 +- frontend/service/Services.ts | 194 +++++++++--------- 8 files changed, 156 insertions(+), 151 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index e461348d3..e97b01b40 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -9,18 +9,18 @@ import { export type ServiceHash = string; -export type LedgerConfig = { - rpc: string; - type: MiddlewareLedger; - chain: MiddlewareChain; -}; - export type ServiceKeys = { address: Address; private_key: string; ledger: MiddlewareChain; }; +export type LedgerConfig = { + rpc: string; + type: MiddlewareLedger; + chain: MiddlewareChain; +}; + export type ChainData = { instances?: Address[]; token?: number; @@ -28,6 +28,7 @@ export type ChainData = { on_chain_state: number; staked: boolean; user_params: { + agent_id: number; cost_of_bond: number; fund_requirements: { agent: number; @@ -36,15 +37,23 @@ export type ChainData = { nft: string; staking_program_id: StakingProgramId; threshold: number; + use_mech_marketplace: true; use_staking: true; }; }; export type MiddlewareServiceResponse = { - name: string; + description: string; hash: string; + hash_history: { + [block: string]: string; + }; + home_chain_id: number; keys: ServiceKeys[]; - readme?: string; + name: string; + service_path?: string; + service_config_id: string; + version: string; chain_configs: { [chainId: number]: { ledger_config: LedgerConfig; @@ -56,18 +65,27 @@ export type MiddlewareServiceResponse = { export type ServiceTemplate = { name: string; hash: string; - image: string; description: string; + image: string; service_version: string; home_chain_id: string; configurations: { [key: string]: ConfigurationTemplate }; deploy?: boolean; + service_env_variables?: { + [key: string]: { + name: string; + env_variable_name: string; + description: string; + value: string; + provision_type: string; + }; + }; }; export type ConfigurationTemplate = { - rpc?: string; // added on deployment staking_program_id?: StakingProgramId; // added on deployment nft: string; + rpc?: string; // added on deployment agent_id: number; threshold: number; use_staking: boolean; @@ -92,37 +110,6 @@ export type Deployment = { nodes: DeployedNodes; }; -export type EmptyPayload = Record; - -export type EmptyResponse = Record; - -export type HttpResponse = { - error?: string; - data?: string; -}; - -export type ClientResponse = { - error?: string; - data?: ResponseType; -}; - -export type StopDeployment = { - delete: boolean /* Delete deployment*/; -}; - -export type UpdateServicePayload = { - old: ServiceHash; - new: ServiceTemplate; -}; - -export type DeleteServicesPayload = { - hashes: ServiceHash[]; -}; - -export type DeleteServicesResponse = { - hashes: ServiceHash[]; -}; - export type AppInfo = { account?: { key: Address; diff --git a/frontend/components/MainPage/header/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton.tsx index d09f31fe1..523669ed0 100644 --- a/frontend/components/MainPage/header/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton.tsx @@ -5,6 +5,7 @@ import { useCallback, useMemo } from 'react'; import { MiddlewareChain, MiddlewareDeploymentStatus } from '@/client'; import { COLOR } from '@/constants/colors'; import { DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider'; +import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; @@ -86,7 +87,7 @@ const AgentRunningButton = () => { // Optimistically update service status setServiceStatus(MiddlewareDeploymentStatus.STOPPING); try { - await ServicesService.stopDeployment(service.hash); + await ServicesService.stopDeployment(service.service_config_id); } catch (error) { console.error(error); showNotification?.('Error while stopping agent'); @@ -205,7 +206,10 @@ const AgentNotRunningButton = () => { serviceTemplate, deploy: true, useMechMarketplace: false, + chainId: ChainId.Gnosis, // TODO: Add support for other chains }); + + await ServicesService.startService(serviceTemplate.service_config_id); } catch (error) { console.error(error); setServiceStatus(undefined); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index f2589d322..59694560d 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -3,6 +3,7 @@ import { isNil } from 'lodash'; import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; +import { ChainId } from '@/enums/Chain'; import { Pages } from '@/enums/Pages'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; @@ -80,13 +81,21 @@ export const MigrateButton = ({ stakingProgramId }: MigrateButtonProps) => { setServiceStatus(MiddlewareDeploymentStatus.DEPLOYING); goto(Pages.Main); - await ServicesService.createService({ + // update service + await ServicesService.updateService({ stakingProgramId, serviceTemplate, + serviceUuid: serviceTemplate.service_config_id, deploy: true, useMechMarketplace: false, + chainId: ChainId.Gnosis, // TODO: Add support for other chains }); + // start service after updating + await ServicesService.startService( + serviceTemplate.service_config_id, + ); + await updateStakingProgram(); setMigrationModalOpen(true); diff --git a/frontend/constants/urls.ts b/frontend/constants/urls.ts index 97afa4d61..392a37a6b 100644 --- a/frontend/constants/urls.ts +++ b/frontend/constants/urls.ts @@ -2,6 +2,8 @@ import { MiddlewareChain } from '@/client'; export const BACKEND_URL: string = `http://localhost:${process.env.NODE_ENV === 'production' ? 8765 : 8000}/api`; +export const BACKEND_URL_V2: string = `http://localhost:${process.env.NODE_ENV === 'production' ? 8765 : 8000}/api/v2`; + export const COW_SWAP_GNOSIS_XDAI_OLAS_URL: string = 'https://swap.cow.fi/#/100/swap/WXDAI/OLAS'; diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 8eec40b9b..6f209dc11 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -59,7 +59,9 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { const selectedService = useMemo(() => { if (!services) return; - return services.find((service) => service.hash === selectedServiceUuid); // TODO: use uuid instead of hash once middleware refactored + return services.find( + (service) => service.service_config_id === selectedServiceUuid, + ); }, [selectedServiceUuid, services]); const selectService = useCallback((serviceUuid: string) => { @@ -68,7 +70,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { useEffect(() => { if (!services) return; - setSelectedServiceUuid(services[0]?.hash); // TODO: use uuid instead of hash once middleware refactored + setSelectedServiceUuid(services[0]?.service_config_id); }, [services]); // const serviceAddresses = useMemo( @@ -107,7 +109,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { // const updateServiceStatus = useCallback(async () => { // if (!services?.[0]) return; - // const serviceStatus = await ServicesService.getDeployment(services[0].hash); + // const serviceStatus = await ServicesService.getDeployment(services[0].service_config_id); // setServiceStatuses(serviceStatus.status); // }, [services]); diff --git a/frontend/hooks/useServiceTemplates.ts b/frontend/hooks/useServiceTemplates.ts index 7e4e733b3..0a6e39d88 100644 --- a/frontend/hooks/useServiceTemplates.ts +++ b/frontend/hooks/useServiceTemplates.ts @@ -3,8 +3,12 @@ import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; export const useServiceTemplates = () => { const getServiceTemplates = (): ServiceTemplate[] => SERVICE_TEMPLATES; - const getServiceTemplate = (hash: string): ServiceTemplate | undefined => - SERVICE_TEMPLATES.find((template) => template.hash === hash); + const getServiceTemplate = ( + serviceUuid: string, + ): ServiceTemplate | undefined => + SERVICE_TEMPLATES.find( + (template) => template.service_config_id === serviceUuid, + ); return { getServiceTemplate, diff --git a/frontend/hooks/useServices.ts b/frontend/hooks/useServices.ts index 1da28a064..957f9ea42 100644 --- a/frontend/hooks/useServices.ts +++ b/frontend/hooks/useServices.ts @@ -52,15 +52,18 @@ export const useServices = () => { const { services, isFetched: hasInitialLoaded } = useContext(ServicesContext); const serviceId = - services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.token; + services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data + ?.token; // STATE METHODS const getServiceFromState = ( - serviceHash: ServiceHash, + serviceUuid: ServiceHash, ): MiddlewareServiceResponse | undefined => { if (!hasInitialLoaded) return; if (!services) return; - return services.find((service) => service.hash === serviceHash); + return services.find( + (service) => service.service_config_id === serviceUuid, + ); }; return { diff --git a/frontend/service/Services.ts b/frontend/service/Services.ts index 596e72736..a80189c77 100644 --- a/frontend/service/Services.ts +++ b/frontend/service/Services.ts @@ -4,8 +4,9 @@ import { ServiceHash, ServiceTemplate, } from '@/client'; +import { CHAIN_CONFIG } from '@/config/chains'; import { CONTENT_TYPE_JSON_UTF8 } from '@/constants/headers'; -import { BACKEND_URL } from '@/constants/urls'; +import { BACKEND_URL_V2 } from '@/constants/urls'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; @@ -15,18 +16,16 @@ import { StakingProgramId } from '@/enums/StakingProgram'; * @returns */ const getService = async ( - serviceHash: ServiceHash, + serviceUuid: ServiceHash, ): Promise => - fetch(`${BACKEND_URL}/services/${serviceHash}`, { + fetch(`${BACKEND_URL_V2}/service/${serviceUuid}`, { method: 'GET', - headers: { - ...CONTENT_TYPE_JSON_UTF8, - }, + headers: { ...CONTENT_TYPE_JSON_UTF8 }, }).then((response) => { if (response.ok) { return response.json(); } - throw new Error(`Failed to fetch service ${serviceHash}`); + throw new Error(`Failed to fetch service ${serviceUuid}`); }); /** @@ -34,11 +33,9 @@ const getService = async ( * @returns An array of services */ const getServices = async (): Promise => - fetch(`${BACKEND_URL}/services`, { + fetch(`${BACKEND_URL_V2}/services`, { method: 'GET', - headers: { - ...CONTENT_TYPE_JSON_UTF8, - }, + headers: { ...CONTENT_TYPE_JSON_UTF8 }, }).then((response) => { if (response.ok) { return response.json(); @@ -56,83 +53,100 @@ const createService = async ({ serviceTemplate, stakingProgramId, useMechMarketplace = false, + chainId, }: { deploy: boolean; serviceTemplate: ServiceTemplate; stakingProgramId: StakingProgramId; useMechMarketplace?: boolean; + chainId: ChainId; }): Promise => - new Promise((resolve, reject) => - fetch(`${BACKEND_URL}/services`, { - method: 'POST', - body: JSON.stringify({ - ...serviceTemplate, - deploy, - configurations: { - [ChainId.Optimism]: { - ...serviceTemplate.configurations[ChainId.Optimism], - staking_program_id: stakingProgramId, - rpc: `${process.env.OPTIMISM_RPC}`, - use_mech_marketplace: useMechMarketplace, - }, + fetch(`${BACKEND_URL_V2}/service`, { + method: 'POST', + body: JSON.stringify({ + ...serviceTemplate, + deploy, + configurations: { + [chainId]: { + ...serviceTemplate.configurations[ChainId.Optimism], + staking_program_id: stakingProgramId, + rpc: CHAIN_CONFIG[chainId].rpc, + use_mech_marketplace: useMechMarketplace, }, - }), - headers: { - ...CONTENT_TYPE_JSON_UTF8, }, - }).then((response) => { - if (response.ok) { - resolve(response.json()); - } - reject(response); }), - ); - -// const deployOnChain = async (serviceHash: ServiceHash): Promise => -// fetch(`${BACKEND_URL}/services/${serviceHash}/onchain/deploy`, { -// method: 'POST', -// headers: { -// ...CONTENT_TYPE_JSON_UTF8, -// }, -// }).then((response) => { -// if (response.ok) { -// return response.json(); -// } -// throw new Error('Failed to deploy service on chain'); -// }); + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + }).then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error('Failed to create service'); + }); -// const buildDeployment = async (serviceHash: ServiceHash): Promise => -// fetch(`${BACKEND_URL}/services/${serviceHash}/deployment/build`, { -// method: 'POST', -// headers: { -// ...CONTENT_TYPE_JSON_UTF8, -// }, -// }).then((response) => { -// if (response.ok) { -// return response.json(); -// } -// throw new Error('Failed to build deployment'); -// }); +/** + * Updates a service + * @param serviceTemplate + * @returns Promise + */ +const updateService = async ({ + deploy, + serviceTemplate, + serviceUuid, + stakingProgramId, + useMechMarketplace = false, + chainId, +}: { + deploy: boolean; + serviceTemplate: ServiceTemplate; + serviceUuid: ServiceHash; + stakingProgramId: StakingProgramId; + useMechMarketplace?: boolean; + chainId: ChainId; +}): Promise => + fetch(`${BACKEND_URL_V2}/service/${serviceUuid}`, { + method: 'PUT', + body: JSON.stringify({ + ...serviceTemplate, + deploy, + configurations: { + [chainId]: { + ...serviceTemplate.configurations[ChainId.Optimism], + staking_program_id: stakingProgramId, + rpc: CHAIN_CONFIG[chainId].rpc, + use_mech_marketplace: useMechMarketplace, + }, + }, + }), + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + }).then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error('Failed to update service'); + }); -// const startDeployment = async (serviceHash: ServiceHash): Promise => -// fetch(`${BACKEND_URL}/services/${serviceHash}/deployment/start`, { -// method: 'POST', -// headers: { -// ...CONTENT_TYPE_JSON_UTF8, -// }, -// }).then((response) => { -// if (response.ok) { -// return response.json(); -// } -// throw new Error('Failed to start deployment'); -// }); +/** + * Starts a service + * @param serviceTemplate + * @returns Promise + */ +const startService = async ( + serviceUuid: ServiceHash, +): Promise => + fetch(`${BACKEND_URL_V2}/service/${serviceUuid}`, { + method: 'POST', + headers: { ...CONTENT_TYPE_JSON_UTF8 }, + }).then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error('Failed to start the service'); + }); -const stopDeployment = async (serviceHash: ServiceHash): Promise => - fetch(`${BACKEND_URL}/services/${serviceHash}/deployment/stop`, { +const stopDeployment = async (serviceUuid: ServiceHash): Promise => + fetch(`${BACKEND_URL_V2}/service/${serviceUuid}/deployment/stop`, { method: 'POST', - headers: { - ...CONTENT_TYPE_JSON_UTF8, - }, + headers: { ...CONTENT_TYPE_JSON_UTF8 }, }).then((response) => { if (response.ok) { return response.json(); @@ -140,27 +154,10 @@ const stopDeployment = async (serviceHash: ServiceHash): Promise => throw new Error('Failed to stop deployment'); }); -// const deleteDeployment = async ( -// serviceHash: ServiceHash, -// ): Promise => -// fetch(`${BACKEND_URL}/services/${serviceHash}/deployment/delete`, { -// method: 'POST', -// headers: { -// ...CONTENT_TYPE_JSON_UTF8, -// }, -// }).then((response) => { -// if (response.ok) { -// return response.json(); -// } -// throw new Error('Failed to delete deployment'); -// }); - -const getDeployment = async (serviceHash: ServiceHash): Promise => - fetch(`${BACKEND_URL}/services/${serviceHash}/deployment`, { +const getDeployment = async (serviceUuid: ServiceHash): Promise => + fetch(`${BACKEND_URL_V2}/service/${serviceUuid}/deployment`, { method: 'GET', - headers: { - ...CONTENT_TYPE_JSON_UTF8, - }, + headers: { ...CONTENT_TYPE_JSON_UTF8 }, }).then((response) => { if (response.ok) { return response.json(); @@ -172,11 +169,8 @@ export const ServicesService = { getService, getServices, getDeployment, + startService, createService, - // deployOnChain, - // stopOnChain, - // buildDeployment, - // startDeployment, + updateService, stopDeployment, - // deleteDeployment, }; From 5978f2bb8b66a6f8492790c954f1b350880a2cb2 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 13:40:36 +0100 Subject: [PATCH 173/463] [no ci] doc: api.md --- api.md | 238 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 151 insertions(+), 87 deletions(-) diff --git a/api.md b/api.md index 145e450bb..7103b5b9c 100644 --- a/api.md +++ b/api.md @@ -1,6 +1,10 @@ -#### `GET /api` +# Olas-Operate API reference -Returns information of the operate daemon +## General + +### `GET /api` + +Returns information of the operate daemon.
Response @@ -19,35 +23,39 @@ Returns information of the operate daemon
--- -#### `GET /api/account` -Returns account status +## Account + +### `GET /api/account` + +Returns account status.
- Before setup + Response -```json -{ - "is_setup": false -} -``` +- Before setup: -
+ ```json + { + "is_setup": false + } + ``` -
- After setup +- After setup: + + ```json + { + "is_setup": true + } + ``` -```json -{ - "is_setup": true -} -```
--- -#### `POST /api/account` -Create a local user account +### `POST /api/account` + +Create a local user account.
Request @@ -63,29 +71,29 @@ Create a local user account
Response -```json -{ - "error": null -} -``` -
+- If account did not exist: -If account already exists + ```json + { + "error": null + } + ``` -
- Response +- If account already exists: + + ```json + { + "error": "Account already exists" + } + ``` -```json -{ - "error": "Account already exists" -} -```
--- -#### `PUT /api/account` -Update password +### `PUT /api/account` + +Update account password.
Request @@ -102,30 +110,30 @@ Update password
Response -```json -{ - "error": null -} -``` -
+- If old password is valid: -Old password is not valid + ```json + { + "error": null + } + ``` -
- Response +- If old password is not valid: + + ```json + { + "error": "Old password is not valid", + "traceback": "..." + } + ``` -```json -{ - "error": "Old password is not valid", - "traceback": "..." -} -```
--- -#### `POST /api/account/login` -Login and create a session +### `POST /api/account/login` + +Login and create a session.
Request @@ -141,15 +149,29 @@ Login and create a session
Response -```json -{ - "message": "Login successful" -} -``` +- If password is valid: + + ```json + { + "message": "Login successful" + } + ``` + +- If password is not valid: + + ```json + { + "error": "Password is not valid" + } + ``` +
--- -#### `GET /api/wallet` + +## Wallet + +### `GET /api/wallet` Returns a list of available wallets @@ -169,12 +191,14 @@ Returns a list of available wallets } ] ``` +
--- -#### `POST /api/wallet` -Creates a master key for given chain type. +### `POST /api/wallet` + +Creates a master wallet for given chain type. If a wallet already exists for a given chain type, it returns the already existing wallet without creating an additional one.
Request @@ -199,13 +223,15 @@ Creates a master key for given chain type. "safes": {}, "safe_nonce": null }, - "mnemonic": [...] + "mnemonic": ["polar", "mail", "tattoo", "write", "track", ... ] } ``` +
--- -#### `POST /api/wallet/safe` + +### `POST /api/wallet/safe` Creates a gnosis safe for given chain type. @@ -223,25 +249,40 @@ Creates a gnosis safe for given chain type.
Response -```json -{ - "address": "0xaaFd5cb31A611C5e5aa65ea8c6226EB4328175E3", - "safe_chains": [ - 2 - ], - "ledger_type": 0, - "safes": { - "2": "0xe56fb574ce2C66008d5c4C09980c4f36Ab81ff22" - }, - "safe_nonce": 110558881674480320952254000342160989674913430251157716140571305138121962898821 -} -``` +- If gnosis safe creation is successful: + + ```json + { + "address": "0xaaFd5cb31A611C5e5aa65ea8c6226EB4328175E3", + "safe_chains": [ + 2 + ], + "ledger_type": 0, + "safes": { + "2": "0xe56fb574ce2C66008d5c4C09980c4f36Ab81ff22" + }, + "safe_nonce": 110558881674480320952254000342160989674913430251157716140571305138121962898821 + } + ``` + +- If gnosis safe creation is not successful: + + ```json + { + "error": "Error message", + "traceback": "Traceback message" + } + ``` +
--- -#### `GET /api/services` -Returns the list of services +## Services + +### `GET /api/v2/services` + +Returns the list of existing services (service configurations).
Response @@ -377,7 +418,8 @@ Optionally you can add `deploy` parameter and set it to `true` for a full deploy
--- -#### `PUT /api/services` + +### `PUT /api/v2/services` Update a service @@ -444,7 +486,8 @@ Optionally you can add `deploy` parameter and set it to `true` for a full deploy
--- -#### `GET /api/services/{service}` + +### `GET /api/v2/services/{service}`
Response @@ -495,7 +538,10 @@ Optionally you can add `deploy` parameter and set it to `true` for a full deploy
--- -#### `POST /api/services/{service}/onchain/deploy` + +### `POST /api/services/{service}/onchain/deploy` + +**:warning: Deprecated** Deploy service on-chain @@ -516,7 +562,10 @@ Deploy service on-chain
--- -#### `POST /api/services/{service}/onchain/stop` + +### `POST /api/services/{service}/onchain/stop` + +**:warning: Deprecated** Stop service on-chain @@ -537,7 +586,10 @@ Stop service on-chain --- -#### `GET /api/services/{service}/deployment` + +### `GET /api/services/{service}/deployment` + +**:warning: Deprecated**
Response @@ -559,7 +611,10 @@ Stop service on-chain
--- -#### `POST /api/services/{service}/deployment/build` + +### `POST /api/services/{service}/deployment/build` + +**:warning: Deprecated** Build service locally @@ -580,7 +635,10 @@ Build service locally --- -#### `POST /api/services/{service}/deployment/start` + +### `POST /api/services/{service}/deployment/start` + +**:warning: Deprecated** Start agent @@ -601,7 +659,10 @@ Start agent --- -#### `POST /api/services/{service}/deployment/stop` + +### `POST /api/services/{service}/deployment/stop` + +**:warning: Deprecated** Stop agent @@ -609,7 +670,10 @@ Stop agent ``` --- -#### `POST /api/services/{service}/deployment/delete` + +### `POST /api/services/{service}/deployment/delete` + +**:warning: Deprecated** Delete local deployment From a142d6d1b41059f92c3b50ea0a94af9560821b34 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 13:43:47 +0100 Subject: [PATCH 174/463] fix: Enum --- frontend/client/types.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 5a9101b14..a02585c5a 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -1,7 +1,7 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; -import { DeploymentStatus, Ledger, MiddlewareChain } from './enums'; +import { DeploymentStatus, Ledger, MiddlewareChain, EnvProvisionType } from './enums'; export type ServiceHash = string; @@ -50,8 +50,6 @@ export type Service = { }; -export type EnvProvisionType = "fixed" | "user" | "computed"; - export type EnvVariableAttributes = { name: string; description: string; From d1853c5da3b21d43b0064f360f0273fc70c8e274 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Wed, 13 Nov 2024 13:57:05 +0000 Subject: [PATCH 175/463] chore: use gnosis in template --- frontend/constants/serviceTemplates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 77017ee73..660f575e0 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -10,7 +10,7 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ image: 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', service_version: 'v0.18.4', - home_chain_id: ChainId.Optimism.toString(), + home_chain_id: ChainId.Gnosis.toString(), configurations: { [ChainId.Optimism]: { staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten From 2b2ba5a66d479181e2d3d1fb11ee14ee2156e074 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 14:15:47 +0000 Subject: [PATCH 176/463] refactor: remove unused constants from MainPage header --- frontend/components/MainPage/header/constants.ts | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 frontend/components/MainPage/header/constants.ts diff --git a/frontend/components/MainPage/header/constants.ts b/frontend/components/MainPage/header/constants.ts deleted file mode 100644 index 27f36a985..000000000 --- a/frontend/components/MainPage/header/constants.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { formatUnits } from 'ethers/lib/utils'; - -import { CHAIN_CONFIG } from '@/config/chains'; -import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; - -export const requiredGas = Number( - formatUnits( - `${SERVICE_TEMPLATES[0].configurations[CHAIN_CONFIG.OPTIMISM.chainId].monthly_gas_estimate}`, - 18, - ), -); From f0b2139a39ddcdaf9488d290062f7fe4208f0e40 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 17:11:11 +0100 Subject: [PATCH 177/463] doc: update api.md --- api.md | 431 +++++++++++++++++++++++++++---------------------- operate/cli.py | 21 ++- 2 files changed, 256 insertions(+), 196 deletions(-) diff --git a/api.md b/api.md index 7103b5b9c..4ed49d22b 100644 --- a/api.md +++ b/api.md @@ -233,7 +233,7 @@ Creates a master wallet for given chain type. If a wallet already exists for a g ### `POST /api/wallet/safe` -Creates a gnosis safe for given chain type. +Creates a Gnosis safe for given chain type.
Request @@ -249,7 +249,7 @@ Creates a gnosis safe for given chain type.
Response -- If gnosis safe creation is successful: +- If Gnosis safe creation is successful: ```json { @@ -265,7 +265,7 @@ Creates a gnosis safe for given chain type. } ``` -- If gnosis safe creation is not successful: +- If Gnosis safe creation is not successful: ```json { @@ -282,7 +282,7 @@ Creates a gnosis safe for given chain type. ### `GET /api/v2/services` -Returns the list of existing services (service configurations). +Returns the list of existing service configurations.
Response @@ -290,128 +290,64 @@ Returns the list of existing services (service configurations). ```json [ { - "hash": "bafybeiha6dxygx2ntgjxhs6zzymgqk3s5biy3ozeqw6zuhr6yxgjlebfmq", - "keys": [ - { - "ledger": 0, - "address": "0x6Db941e0e82feA3c02Ba83B20e3fB5Ea6ee539cf", - "private_key": "0x34f58dcc11acec007644e49921fd81b9c8a959f651d6d66a42242a1b2dbaf4be" - } - ], - "ledger_config": { - "rpc": "http://localhost:8545", - "type": 0, - "chain": 2 - }, - "chain_data": { - "instances": [ - "0x6Db941e0e82feA3c02Ba83B20e3fB5Ea6ee539cf" - ], - "token": 380, - "multisig": "0x7F3e460Cf596E783ca490791643C0055Fa2034AC", - "staked": false, - "on_chain_state": 6, - "user_params": { - "nft": "bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq", - "agent_id": 14, - "threshold": 1, - "use_staking": false, - "cost_of_bond": 10000000000000000, - "olas_cost_of_bond": 10000000000000000000, - "olas_required_to_stake": 10000000000000000000, - "fund_requirements": { - "agent": 0.1, - "safe": 0.5 - } - } - }, - "path": "/Users/virajpatel/valory/olas-operate-app/.operate/services/bafybeiha6dxygx2ntgjxhs6zzymgqk3s5biy3ozeqw6zuhr6yxgjlebfmq", - "service_path": "/Users/virajpatel/valory/olas-operate-app/.operate/services/bafybeiha6dxygx2ntgjxhs6zzymgqk3s5biy3ozeqw6zuhr6yxgjlebfmq/trader_omen_gnosis", - "name": "valory/trader_omen_gnosis" - } + "chain_configs": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, + "home_chain_id": "100", + "keys": [...], + "name": "valory/trader_omen_gnosis", + "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", + "service_path": "/home/user/.operate/services/sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39/trader_omen_gnosis", + "version": 4 + }, + ... ] ```
--- -#### `POST /api/services` -Create a service using the service template +#### `POST /api/v2/services` + +Create a service configuration using a template.
Request ```json -{ - "name": "Trader Agent", - "description": "Trader agent for omen prediction markets", - "hash": "bafybeiha6dxygx2ntgjxhs6zzymgqk3s5biy3ozeqw6zuhr6yxgjlebfmq", - "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", - "configuration": { - "nft": "bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq", - "rpc": "http://localhost:8545", - "agent_id": 14, - "threshold": 1, - "use_staking": false, - "cost_of_bond": 10000000000000000, - "olas_cost_of_bond": 10000000000000000000, - "olas_required_to_stake": 10000000000000000000, - "fund_requirements": { - "agent": 0.1, - "safe": 0.5 - } + { + "configurations": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", + "home_chain_id": "100", + "name": "valory/trader_omen_gnosis", + "service_version": "v0.18.4" } -} ```
-Optionally you can add `deploy` parameter and set it to `true` for a full deployment in a single request. -
Response ```json { - "hash": "bafybeiha6dxygx2ntgjxhs6zzymgqk3s5biy3ozeqw6zuhr6yxgjlebfmq", - "keys": [ - { - "ledger": 0, - "address": "0x10EB940024913dfCAE95D21E04Ba662cdfB79fF0", - "private_key": "0x00000000000000000000000000000000000000000000000000000000000000000" - } - ], - "ledger_config": { - "rpc": "http: //localhost:8545", - "type": 0, - "chain": 2 - }, - "chain_data": { - "instances": [ - "0x10EB940024913dfCAE95D21E04Ba662cdfB79fF0" - ], - "token": 382, - "multisig": "0xf21d8A424e83BBa2588306D1C574FE695AD410b5", - "staked": false, - "on_chain_state": 4, - "user_params": { - "nft": "bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq", - "agent_id": 14, - "threshold": 1, - "use_staking": false, - "cost_of_bond": 10000000000000000, - "olas_cost_of_bond": 10000000000000000000, - "olas_required_to_stake": 10000000000000000000, - "fund_requirements": { - "agent": 0.1, - "safe": 0.5 - } - } - }, - "path": "~/.operate/services/bafybeiha6dxygx2ntgjxhs6zzymgqk3s5biy3ozeqw6zuhr6yxgjlebfmq", - "service_path": "~/.operate/services/bafybeiha6dxygx2ntgjxhs6zzymgqk3s5biy3ozeqw6zuhr6yxgjlebfmq/trader_omen_gnosis", - "name": "valory/trader_omen_gnosis" + "chain_configs": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, + "home_chain_id": "100", + "keys": [...], + "name": "valory/trader_omen_gnosis", + "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", + "service_path": "/home/user/.operate/services/sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39/trader_omen_gnosis", + "version": 4 } ``` @@ -421,124 +357,239 @@ Optionally you can add `deploy` parameter and set it to `true` for a full deploy ### `PUT /api/v2/services` -Update a service +Update all the service configurations whose Service Public ID match the Service Public ID in the provided hash.
Request ```json -{ - "old_service_hash": "bafybeiha6dxygx2ntgjxhs6zzymgqk3s5biy3ozeqw6zuhr6yxgjlebfmq", - "new_service_hash": "bafybeicxdpkuk5z5zfbkso7v5pywf4v7chxvluyht7dtgalg6dnhl7ejoe", -} + { + "configurations": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me", + "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", + "home_chain_id": "100", + "name": "valory/trader_omen_gnosis", + "service_version": "v0.19.0" + } ```
-Optionally you can add `deploy` parameter and set it to `true` for a full deployment in a single request. -
Response +The response contains an array of the services which have been updated (an empty array if no service matches the Service Public ID in the provided hash). + ```json -{ - "hash": "bafybeicxdpkuk5z5zfbkso7v5pywf4v7chxvluyht7dtgalg6dnhl7ejoe", - "keys": [ - { - "ledger": 0, - "address": "0x10EB940024913dfCAE95D21E04Ba662cdfB79fF0", - "private_key": "0x00000000000000000000000000000000000000000000000000000000000000000" - } - ], - "ledger_config": { - "rpc": "http: //localhost:8545", - "type": 0, - "chain": 2 - }, - "chain_data": { - "instances": [ - "0x10EB940024913dfCAE95D21E04Ba662cdfB79fF0" - ], - "token": 382, - "multisig": "0xf21d8A424e83BBa2588306D1C574FE695AD410b5", - "staked": false, - "on_chain_state": 4, - "user_params": { - "nft": "bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq", - "agent_id": 14, - "threshold": 1, - "use_staking": false, - "cost_of_bond": 10000000000000000, - "olas_cost_of_bond": 10000000000000000000, - "olas_required_to_stake": 10000000000000000000, - "fund_requirements": { - "agent": 0.1, - "safe": 0.5 - } - } +[ + { + "chain_configs": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "1731490000": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me"}, + "home_chain_id": "100", + "keys": [...], + "name": "valory/trader_omen_gnosis", + "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", + "service_path": "/home/user/.operate/services/sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39/trader_omen_gnosis", + "version": 4 }, - "path": "~/.operate/services/bafybeicxdpkuk5z5zfbkso7v5pywf4v7chxvluyht7dtgalg6dnhl7ejoe", - "service_path": "~/.operate/services/bafybeicxdpkuk5z5zfbkso7v5pywf4v7chxvluyht7dtgalg6dnhl7ejoe/trader_omen_gnosis", - "name": "valory/trader_omen_gnosis" -} + ... +] ```
--- -### `GET /api/v2/services/{service}` +#### `POST /api/v2/services/stop` (alias `GET /stop_all_services`) + +Stop all running deployments. + +
+ Response + +- If the operation was successful: + + ```json + { + "message": "Services stopped." + } + ``` + +- If the operation was not successful: + + ```json + { + "error": "Error message", + "traceback": "Traceback message" + } + ``` + +
+ +--- + +## Service + +### `GET /api/v2/service/{service_config_id}` + +Returns the service configuration `service_config_id`. + +
+ Response + +- If service configuration `service_config_id` exists: + + ```json + { + "chain_configs": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, + "home_chain_id": "100", + "keys": [...], + "name": "valory/trader_omen_gnosis", + "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", + "service_path": "/home/user/.operate/services/sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39/trader_omen_gnosis", + "version": 4 + } + + ``` + +- If service configuration `service_config_id` does not exist: + + ```json + { + "error": "Service foo not found" + } + ``` + +
+ +--- + +### `POST /api/v2/service/{service_config_id}` + +Deploy service with service configuration `service_config_id` on-chain and run local deployment. This endpoint executes the following tasks: + +1. Stops any running service. +2. Ensures that the service is deployed on-chain on all the configured chains. +3. Ensures that the the service is staked on all the configured chains. +4. Runs the service locally. +5. Starts funding job. +6. Starts healthcheck job. + +
Response +The response contains the updated service configuration following the on-chain operations, including service Gnosis safe, on-chain token, etc. + ```json { - "hash": "{service}", - "keys": [ - { - "ledger": 0, - "address": "0x10EB940024913dfCAE95D21E04Ba662cdfB79fF0", - "private_key": "0x00000000000000000000000000000000000000000000000000000000000000000" - } - ], - "ledger_config": { - "rpc": "http: //localhost:8545", - "type": 0, - "chain": 2 - }, - "chain_data": { - "instances": [ - "0x10EB940024913dfCAE95D21E04Ba662cdfB79fF0" - ], - "token": 382, - "multisig": "0xf21d8A424e83BBa2588306D1C574FE695AD410b5", - "staked": false, - "on_chain_state": 4, - "user_params": { - "nft": "bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq", - "agent_id": 14, - "threshold": 1, - "use_staking": false, - "cost_of_bond": 10000000000000000, - "olas_cost_of_bond": 10000000000000000000, - "olas_required_to_stake": 10000000000000000000, - "fund_requirements": { - "agent": 0.1, - "safe": 0.5 - } - } - }, - "path": "~/.operate/services/{service}", - "service_path": "~/.operate/services/{service}/trader_omen_gnosis", - "name": "valory/trader_omen_gnosis" + "chain_configs": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, + "home_chain_id": "100", + "keys": [...], + "name": "valory/trader_omen_gnosis", + "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", + "service_path": "/home/user/.operate/services/sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39/trader_omen_gnosis" } + +``` + +
+ +--- + +### `PUT /api/v2/service/{service_config_id}` + +Update service configuration `service_config_id` with the provided template. + +
+ Request + +```json + { + "configurations": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me", + "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", + "home_chain_id": "100", + "name": "valory/trader_omen_gnosis", + "service_version": "v0.19.0" + } +``` + +
+ +
+ Response + +- If the update is successful, the response contains the updated service configuration: + + ```json + { + "chain_configs": {...}, + "description": "Trader agent for omen prediction markets", + "env_variables": {...}, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "1731490000": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me"}, + "home_chain_id": "100", + "keys": [...], + "name": "valory/trader_omen_gnosis", + "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", + "service_path": "/home/user/.operate/services/sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39/trader_omen_gnosis" + } + + ``` + +- If the update is not successful: + + ```json + { + "error": "Error message", + "traceback": "Traceback message" + } + ``` + +
+ +--- + +### `POST /api/service/{service_config_id}/stop` + +Stop service with service configuration `service_configuration_id`. + +
+ Response + +```json + { + "nodes": { + "agent": [], + "tendermint": [] + }, + "status": 1 + } ```
--- +## Unused endpoints + ### `POST /api/services/{service}/onchain/deploy` **:warning: Deprecated** @@ -711,5 +762,3 @@ Delete local deployment
--> - - diff --git a/operate/cli.py b/operate/cli.py index ad558430e..eee71f2bf 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -303,12 +303,23 @@ async def _kill_server(request: Request) -> JSONResponse: """Kill backend server from inside.""" os.kill(os.getpid(), signal.SIGINT) + @app.post("/api/v2/services/stop") @app.get("/stop_all_services") async def _stop_all_services(request: Request) -> JSONResponse: """Kill backend server from inside.""" - logger.info("Stopping services on demand...") - pause_all_services() - logger.info("Stopping services on demand done.") + + # No authentication required to stop services. + + try: + logger.info("Stopping services on demand...") + pause_all_services() + logger.info("Stopping services on demand done.") + return JSONResponse(content={"message": "Services stopped."}) + except Exception as e: # pylint: disable=broad-except + return JSONResponse( + content={"error": str(e), "traceback": traceback.format_exc()}, + status_code=500, + ) @app.get("/api") @with_retries @@ -732,8 +743,8 @@ async def _update_all_services(request: Request) -> JSONResponse: @with_retries async def _stop_service_locally(request: Request) -> JSONResponse: """Stop a service deployment.""" - if operate.password is None: - return USER_NOT_LOGGED_IN_ERROR + + # No authentication required to stop services. service_config_id = request.path_params["service_config_id"] manager = operate.service_manager() From 25007488155c08c27b56b927b544796e4dd1a5d2 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 17:39:49 +0100 Subject: [PATCH 178/463] fix: linters --- operate/cli.py | 2 +- operate/services/health_checker.py | 4 +++- operate/services/service.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index eee71f2bf..4d07961d3 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -743,7 +743,7 @@ async def _update_all_services(request: Request) -> JSONResponse: @with_retries async def _stop_service_locally(request: Request) -> JSONResponse: """Stop a service deployment.""" - + # No authentication required to stop services. service_config_id = request.path_params["service_config_id"] diff --git a/operate/services/health_checker.py b/operate/services/health_checker.py index a6f709724..86bd5353b 100644 --- a/operate/services/health_checker.py +++ b/operate/services/health_checker.py @@ -174,7 +174,9 @@ def _do_restart() -> None: service_manager.stop_service_locally( service_config_id=service_config_id ) - service_manager.deploy_service_locally(service_config_id=service_config_id) + service_manager.deploy_service_locally( + service_config_id=service_config_id + ) loop = asyncio.get_event_loop() with ThreadPoolExecutor() as executor: diff --git a/operate/services/service.py b/operate/services/service.py index c6302ad81..c16d9b4d0 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -76,13 +76,13 @@ DeployedNodes, DeploymentConfig, DeploymentStatus, + EnvVariables, LedgerConfig, LedgerConfigs, LedgerType, OnChainData, OnChainState, OnChainUserParams, - EnvVariables, ServiceTemplate, ) from operate.resource import LocalResource From a472fa6cf2752e576bca272d1155f42cace0199e Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 17:51:07 +0100 Subject: [PATCH 179/463] chore: minor change --- operate/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operate/cli.py b/operate/cli.py index 4d07961d3..d1763f151 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -513,7 +513,7 @@ async def _create_safe(request: Request) -> t.List[t.Dict]: return JSONResponse( content={ "safe": wallet.safes.get(chain_type), - "message": "Safe already exists!", + "message": f"Safe already exists {chain_type=}.", } ) From 61f63fe7770c94645b6a6b1f603f0e3a4ef3c8bf Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 18:24:13 +0100 Subject: [PATCH 180/463] chore: fix contract --- operate/data/README.md | 8 ++++++++ operate/data/contracts/README.md | 8 -------- operate/data/contracts/staking_token/__init__.py | 2 +- operate/data/contracts/staking_token/contract.py | 2 +- operate/data/contracts/staking_token/contract.yaml | 6 +++--- 5 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 operate/data/README.md delete mode 100644 operate/data/contracts/README.md diff --git a/operate/data/README.md b/operate/data/README.md new file mode 100644 index 000000000..7860c2ac2 --- /dev/null +++ b/operate/data/README.md @@ -0,0 +1,8 @@ +# Contracts Data + +This directory contains packages that are used in the middleware. + +- `contracts/staking_token` is copied from [valory/trader](https://github.com/valory-xyz/trader/tree/main/packages/valory/contracts/staking_token) +- `contracts/uniswap_v2_erc20` is copied from [valory/optimus-quickstart](https://github.com/valory-xyz/optimus-quickstart/tree/main/operate/data/contracts/uniswap_v2_erc20) + +TODO: Have a better way to import and reuse packages in the middleware. diff --git a/operate/data/contracts/README.md b/operate/data/contracts/README.md deleted file mode 100644 index eb2ef88f3..000000000 --- a/operate/data/contracts/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Contracts Data - -This directory contains contract packages that are used in the middleware. - -- `staking_token` is copied from [valory/trader](https://github.com/valory-xyz/trader/tree/0f7ac7d77449d434bdc93c703bd3e0e82561eda9/packages/valory/contracts/staking_token) -- `uniswap_v2_erc20` is copied from [valory/optimus-quickstart](https://github.com/valory-xyz/optimus-quickstart/tree/a7e65d2a741bfa749a54d57b80205a477d303cc1/operate/data/contracts/uniswap_v2_erc20) - -TODO: Have a better way to import and reuse these packages accross repositories instead of copying them. diff --git a/operate/data/contracts/staking_token/__init__.py b/operate/data/contracts/staking_token/__init__.py index dbe126167..4682f8155 100644 --- a/operate/data/contracts/staking_token/__init__.py +++ b/operate/data/contracts/staking_token/__init__.py @@ -17,4 +17,4 @@ # # ------------------------------------------------------------------------------ -"""This module contains the support resources for the staking token contract.""" \ No newline at end of file +"""This module contains the support resources for the staking contract.""" diff --git a/operate/data/contracts/staking_token/contract.py b/operate/data/contracts/staking_token/contract.py index 572320f13..8bc883783 100644 --- a/operate/data/contracts/staking_token/contract.py +++ b/operate/data/contracts/staking_token/contract.py @@ -189,4 +189,4 @@ def get_min_staking_duration( """Retrieve the service IDs.""" contract = cls.get_instance(ledger_api, contract_address) duration = contract.functions.minStakingDuration().call() - return dict(data=duration) \ No newline at end of file + return dict(data=duration) diff --git a/operate/data/contracts/staking_token/contract.yaml b/operate/data/contracts/staking_token/contract.yaml index 6441378b6..e1a858361 100644 --- a/operate/data/contracts/staking_token/contract.yaml +++ b/operate/data/contracts/staking_token/contract.yaml @@ -6,9 +6,9 @@ description: Service staking token contract license: Apache-2.0 aea_version: '>=1.0.0, <2.0.0' fingerprint: - __init__.py: bafybeief433natrcgivlwhdrrnovqusgfaywlstaauk7qrgatpzmikdmre + __init__.py: bafybeicmgkagyhgwn2ktcdjbprijalbdyj26cvza4d3b7uvmehvy4mmr3i build/StakingToken.json: bafybeibhcwyawq377innrpq4ytpw5kotufjqo7cyd2rjhyit34mnbks5b4 - contract.py: bafybeiheojdt5kwyvkmzta5jh7xznbxdcls2ossx4lv7llh3rwhtcj5lyi + contract.py: bafybeigjt7a2biiorp4vmj4d3qkm3xbbohnawoetywojye5akhavlvkrxm fingerprint_ignore_patterns: [] contracts: [] class_name: StakingTokenContract @@ -20,4 +20,4 @@ dependencies: open-aea-test-autonomy: version: <1,>=0.14.14.post1 web3: - version: <7,>=6.0.0 \ No newline at end of file + version: <7,>=6.0.0 From 857d93fffeac0a3d024872cf8f84b3940535b584 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 18:46:01 +0100 Subject: [PATCH 181/463] fix: usage of chain_id --- operate/services/manage.py | 5 ++--- operate/services/service.py | 34 +++++++++++++++++++++------------- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 1803c1f89..99a881892 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -1525,14 +1525,13 @@ def deploy_service_locally( :param hash: Service hash :param force: Remove previous deployment and start a new one. + :param chain_id: Chain ID to set runtime parameters on the deployment (home_chain_id if not provided). + :param use_docker: Use a Docker Compose deployment (True) or Host deployment (False). :return: Deployment instance """ self._set_env_variables(service_config_id=service_config_id) service = self.load(service_config_id=service_config_id) - if not chain_id: - chain_id = service.home_chain_id - deployment = service.deployment deployment.build(use_docker=use_docker, force=force, chain_id=chain_id) deployment.start(use_docker=use_docker) diff --git a/operate/services/service.py b/operate/services/service.py index c16d9b4d0..5736005be 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -394,7 +394,7 @@ def load(cls, path: Path) -> "Deployment": def _build_docker( self, force: bool = True, - chain_id: str = "100", + chain_id: t.Optional[str] = None, ) -> None: """Build docker deployment.""" service = Service.load(path=self.path) @@ -437,20 +437,23 @@ 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].chain_data - home_chain_ledger_config = service.chain_configs[ - service.home_chain_id - ].ledger_config + if not chain_id: + chain_id = service.home_chain_id + + chain_config = service.chain_configs[chain_id] + ledger_config = chain_config.ledger_config + chain_data = chain_config.chain_data + builder.try_update_runtime_params( - multisig_address=home_chain_data.multisig, - agent_instances=home_chain_data.instances, - service_id=home_chain_data.token, + multisig_address=chain_data.multisig, + agent_instances=chain_data.instances, + service_id=chain_data.token, consensus_threshold=None, ) # TODO: Support for multiledger builder.try_update_ledger_params( - chain=LedgerType(home_chain_ledger_config.type).name.lower(), - address=home_chain_ledger_config.rpc, + chain=LedgerType(ledger_config.type).name.lower(), + address=ledger_config.rpc, ) # build deployment @@ -498,7 +501,7 @@ def _build_docker( self.status = DeploymentStatus.BUILT self.store() - def _build_host(self, force: bool = True, chain_id: str = "100") -> None: + def _build_host(self, force: bool = True, chain_id: t.Optional[str] = None) -> None: """Build host depployment.""" build = self.path / DEPLOYMENT if build.exists() and not force: @@ -522,6 +525,9 @@ def _build_host(self, force: bool = True, chain_id: str = "100") -> None: "Host deployment currently only supports single agent deployments" ) + if not chain_id: + chain_id = service.home_chain_id + chain_config = service.chain_configs[chain_id] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data @@ -585,16 +591,18 @@ def build( self, use_docker: bool = False, force: bool = True, - chain_id: str = "100", + chain_id: t.Optional[str] = None, ) -> None: """ Build a deployment - :param use_docker: Use docker deployment + :param use_docker: Use a Docker Compose deployment (True) or Host deployment (False). :param force: Remove existing deployment and build a new one + :param chain_id: Chain ID to set runtime parameters on the deployment (home_chain_id if not provided). :return: Deployment object """ # TODO: chain_id should be used properly! Added as a hotfix for now. + # Maybe remove usage of chain_id and use home_chain_id always? if use_docker: return self._build_docker(force=force, chain_id=chain_id) return self._build_host(force=force, chain_id=chain_id) From f5576b528771e0fc443e01668d5142557068f601 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 19:00:38 +0100 Subject: [PATCH 182/463] chore: update comment --- operate/services/service.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/operate/services/service.py b/operate/services/service.py index 5736005be..b6ed4c643 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -601,8 +601,7 @@ def build( :param chain_id: Chain ID to set runtime parameters on the deployment (home_chain_id if not provided). :return: Deployment object """ - # TODO: chain_id should be used properly! Added as a hotfix for now. - # Maybe remove usage of chain_id and use home_chain_id always? + # TODO: Maybe remove usage of chain_id and use home_chain_id always? if use_docker: return self._build_docker(force=force, chain_id=chain_id) return self._build_host(force=force, chain_id=chain_id) From cbdf00e7ea3c57e30dac982f92ba848d768431d6 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 19:17:51 +0100 Subject: [PATCH 183/463] chore: integrate changes from optimus operate --- operate/ledger/profiles.py | 4 +++- operate/services/manage.py | 31 ++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/operate/ledger/profiles.py b/operate/ledger/profiles.py index db1c53a37..ad983acad 100644 --- a/operate/ledger/profiles.py +++ b/operate/ledger/profiles.py @@ -90,7 +90,9 @@ }, ChainType.ETHEREUM: {}, ChainType.BASE: {}, - ChainType.MODE: {}, + ChainType.MODE: { + "optimus_alpha": "0x5fc25f50E96857373C64dC0eDb1AbCBEd4587e91", + }, } OLAS = { diff --git a/operate/services/manage.py b/operate/services/manage.py index 99a881892..d8d0c84d6 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -1370,26 +1370,27 @@ def fund_service_single_chain( # pylint: disable=too-many-arguments,too-many-lo chain_type=ledger_config.chain, rpc=rpc or ledger_config.rpc ) agent_fund_threshold = ( - agent_fund_threshold or chain_data.user_params.fund_requirements.agent + agent_fund_threshold if agent_fund_threshold is not None else chain_data.user_params.fund_requirements.agent ) for key in service.keys: agent_balance = ledger_api.get_balance(address=key.address) self.logger.info(f"Agent {key.address} balance: {agent_balance}") - self.logger.info(f"Required balance: {agent_fund_threshold}") - if agent_balance < agent_fund_threshold: - self.logger.info("Funding agents") - to_transfer = ( - agent_topup or chain_data.user_params.fund_requirements.agent - ) - self.logger.info(f"Transferring {to_transfer} units to {key.address}") - wallet.transfer( - to=key.address, - amount=int(to_transfer), - chain_type=ledger_config.chain, - from_safe=from_safe, - rpc=rpc or ledger_config.rpc, - ) + if agent_fund_threshold > 0: + self.logger.info(f"Required balance: {agent_fund_threshold}") + if agent_balance < agent_fund_threshold: + self.logger.info("Funding agents") + to_transfer = ( + agent_topup or chain_data.user_params.fund_requirements.agent + ) + self.logger.info(f"Transferring {to_transfer} units to {key.address}") + wallet.transfer( + to=key.address, + amount=int(to_transfer), + chain_type=ledger_config.chain, + from_safe=from_safe, + rpc=rpc or ledger_config.rpc, + ) safe_balance = ledger_api.get_balance(chain_data.multisig) safe_fund_treshold = ( From fafc2f7e5b86fcb3f0f01361d6532571635c6d4b Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 20:50:19 +0100 Subject: [PATCH 184/463] fix: pylint --- operate/services/manage.py | 71 +++++++++++++++---------------------- operate/services/service.py | 44 ++++++++++++++++++----- 2 files changed, 64 insertions(+), 51 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index d8d0c84d6..c008aa322 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -41,7 +41,6 @@ from operate.operate_types import ( ChainType, LedgerConfig, - ServiceEnvProvisionType, ServiceTemplate, ) from operate.services.protocol import EthSafeTxBuilder, OnChainManager, StakingState @@ -237,44 +236,6 @@ def create( return service - def _compute_service_env_variables( - self, service: Service, staking_params: t.Dict[str, str] - ) -> None: - """Compute values to override service.yaml variables for the deployment.""" - - # TODO A customized, arbitrary computation mechanism should be devised. - computed_values = { - "ETHEREUM_LEDGER_RPC": PUBLIC_RPCS[ChainType.ETHEREUM], - "GNOSIS_LEDGER_RPC": PUBLIC_RPCS[ChainType.GNOSIS], - "BASE_LEDGER_RPC": PUBLIC_RPCS[ChainType.BASE], - "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[ChainType.OPTIMISM], - "STAKING_CONTRACT_ADDRESS": staking_params.get("staking_contract"), - "MECH_ACTIVITY_CHECKER_CONTRACT": staking_params.get("activity_checker"), - "MECH_CONTRACT_ADDRESS": staking_params.get("agent_mech"), - "MECH_REQUEST_PRICE": "10000000000000000", - "USE_MECH_MARKETPLACE": "mech_marketplace" - in service.chain_configs[ - service.home_chain_id - ].chain_data.user_params.staking_program_id, - "REQUESTER_STAKING_INSTANCE_ADDRESS": staking_params.get( - "staking_contract" - ), - "PRIORITY_MECH_ADDRESS": staking_params.get("agent_mech"), - } - - updated = False - for env_var, attributes in service.env_variables.items(): - if ( - env_var in computed_values - and attributes["provision_type"] == ServiceEnvProvisionType.COMPUTED - and attributes["value"] != computed_values.get(env_var) - ): - attributes["value"] = str(computed_values.get(env_var)) - updated = True - - if updated: - service.store() - 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 @@ -574,7 +535,29 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to agent_mech="0x77af31De935740567Cf4fF1986D04B2c964A786a", # nosec ) - self._compute_service_env_variables(service, staking_params) + # TODO A customized, arbitrary computation mechanism should be devised. + env_var_to_value = { + "ETHEREUM_LEDGER_RPC": PUBLIC_RPCS[ChainType.ETHEREUM], + "GNOSIS_LEDGER_RPC": PUBLIC_RPCS[ChainType.GNOSIS], + "BASE_LEDGER_RPC": PUBLIC_RPCS[ChainType.BASE], + "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[ChainType.OPTIMISM], + "STAKING_CONTRACT_ADDRESS": staking_params.get("staking_contract"), + "MECH_ACTIVITY_CHECKER_CONTRACT": staking_params.get("activity_checker"), + "MECH_CONTRACT_ADDRESS": staking_params.get("agent_mech"), + "MECH_REQUEST_PRICE": "10000000000000000", + "USE_MECH_MARKETPLACE": str( + "mech_marketplace" + in service.chain_configs[ + service.home_chain_id + ].chain_data.user_params.staking_program_id + ), + "REQUESTER_STAKING_INSTANCE_ADDRESS": staking_params.get( + "staking_contract" + ), + "PRIORITY_MECH_ADDRESS": staking_params.get("agent_mech"), + } + + service.update_env_variables_values(env_var_to_value) if user_params.use_staking: self.logger.info("Checking staking compatibility") @@ -1370,7 +1353,9 @@ def fund_service_single_chain( # pylint: disable=too-many-arguments,too-many-lo chain_type=ledger_config.chain, rpc=rpc or ledger_config.rpc ) agent_fund_threshold = ( - agent_fund_threshold if agent_fund_threshold is not None else chain_data.user_params.fund_requirements.agent + agent_fund_threshold + if agent_fund_threshold is not None + else chain_data.user_params.fund_requirements.agent ) for key in service.keys: @@ -1383,7 +1368,9 @@ def fund_service_single_chain( # pylint: disable=too-many-arguments,too-many-lo to_transfer = ( agent_topup or chain_data.user_params.fund_requirements.agent ) - self.logger.info(f"Transferring {to_transfer} units to {key.address}") + self.logger.info( + f"Transferring {to_transfer} units to {key.address}" + ) wallet.transfer( to=key.address, amount=int(to_transfer), diff --git a/operate/services/service.py b/operate/services/service.py index b6ed4c643..690ca3dee 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -84,6 +84,7 @@ OnChainState, OnChainUserParams, ServiceTemplate, + ServiceEnvProvisionType, ) from operate.resource import LocalResource from operate.services.deployment_runner import run_host_deployment, stop_host_deployment @@ -596,7 +597,7 @@ def build( """ Build a deployment - :param use_docker: Use a Docker Compose deployment (True) or Host deployment (False). + :param use_docker: Use a Docker Compose deployment (True) or Host deployment (False). :param force: Remove existing deployment and build a new one :param chain_id: Chain ID to set runtime parameters on the deployment (home_chain_id if not provided). :return: Deployment object @@ -786,11 +787,6 @@ def migrate_format(cls, path: Path) -> bool: return True - def consume_env_variables(self) -> None: - """Consume environment variables.""" - for env_var, attributes in self.env_variables.items(): - os.environ[env_var] = str(attributes["value"]) - @classmethod def load(cls, path: Path) -> "Service": """Load a service""" @@ -871,7 +867,6 @@ def new( # pylint: disable=too-many-locals service.store() return service - @property def service_public_id(self, include_version: bool = True) -> str: """Get the public id (based on the service hash).""" with (self.service_path / "service.yaml").open("r", encoding="utf-8") as fp: @@ -934,10 +929,10 @@ def update( target_service_public_id = Service.get_service_public_id(target_hash, self.path) if not allow_different_service_public_id and ( - self.service_public_id != target_service_public_id + self.service_public_id() != target_service_public_id ): raise ValueError( - f"Trying to update a service with a different public id: {self.service_public_id=} {self.hash=} {target_service_public_id=} {target_hash=}." + f"Trying to update a service with a different public id: {self.service_public_id()=} {self.hash=} {target_service_public_id=} {target_hash=}." ) shutil.rmtree(self.service_path) @@ -1007,6 +1002,37 @@ def update_user_params_from_template( self.store() + def consume_env_variables(self) -> None: + """Consume (apply) environment variables.""" + for env_var, attributes in self.env_variables.items(): + os.environ[env_var] = str(attributes["value"]) + + def update_env_variables_values( + self, env_var_to_value: t.Dict[str, str], except_if_undefined: bool = False + ) -> None: + """Updates and stores the values of the env variables to override service.yaml on the deployment. + This method does not apply the variables to the environment. Use consume_env_variables to apply the + env variables.""" + + updated = False + for var, value in env_var_to_value.items(): + attributes = self.env_variables.get(var) + if ( + attributes + and self.env_variables[var]["provision_type"] + == ServiceEnvProvisionType.COMPUTED + and attributes["value"] != value + ): + attributes["value"] = str(value) + updated = True + elif except_if_undefined: + raise ValueError( + f"Trying to set value for an environment variable ({var}) not present on service configuration {self.service_config_id}." + ) + + if updated: + self.store() + def delete(self) -> None: """Delete a service.""" parent_directory = self.path.parent From e0bff70e86ec8b107b033eb40184357e51006f6c Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 20:51:26 +0100 Subject: [PATCH 185/463] chore: linters --- operate/services/manage.py | 6 +----- operate/services/service.py | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index c008aa322..55e886c5c 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -38,11 +38,7 @@ from operate.keys import Key, KeysManager from operate.ledger import PUBLIC_RPCS from operate.ledger.profiles import CONTRACTS, OLAS, STAKING -from operate.operate_types import ( - ChainType, - LedgerConfig, - ServiceTemplate, -) +from operate.operate_types import ChainType, LedgerConfig, ServiceTemplate from operate.services.protocol import EthSafeTxBuilder, OnChainManager, StakingState from operate.services.service import ( ChainConfig, diff --git a/operate/services/service.py b/operate/services/service.py index 690ca3dee..76d833bd6 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -83,8 +83,8 @@ OnChainData, OnChainState, OnChainUserParams, - ServiceTemplate, ServiceEnvProvisionType, + ServiceTemplate, ) from operate.resource import LocalResource from operate.services.deployment_runner import run_host_deployment, stop_host_deployment From 00f1245d2b8114220878cca01d41c92c02041dd0 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 20:55:28 +0100 Subject: [PATCH 186/463] chore: fix linters --- operate/cli.py | 195 ------------------------------------ operate/services/manage.py | 2 +- operate/services/service.py | 7 +- tox.ini | 1 + 4 files changed, 7 insertions(+), 198 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index d1763f151..cf5ac7639 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -764,201 +764,6 @@ async def _stop_service_locally(request: Request) -> JSONResponse: cancel_funding_job(service_config_id=service_config_id) return JSONResponse(content=deployment.json) - # @app.post("/api/services") - # @with_retries - # async def _create_services(request: Request) -> JSONResponse: - # """Create a service.""" - # if operate.password is None: - # return USER_NOT_LOGGED_IN_ERROR - # template = await request.json() - # manager = operate.service_manager() - # if len(manager.json) > 0: - # old_hash = manager.json[0]["hash"] - # if old_hash == template["hash"]: - # logger.info(f'Loading service {template["hash"]}') - # service = manager.load_or_create( - # hash=template["hash"], - # service_template=template, - # ) - # else: - # logger.info(f"Updating service from {old_hash} to " + template["hash"]) - # service = manager.update_service( - # old_hash=old_hash, - # new_hash=template["hash"], - # service_template=template, - # ) - # else: - # logger.info(f'Creating service {template["hash"]}') - # service = manager.load_or_create( - # hash=template["hash"], - # service_template=template, - # ) - - # 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(service_config_id=service.service_config_id) - # manager.fund_service(service_config_id=service_config_id) - # manager.deploy_service_locally(service_config_id=service_config_id) - - # await run_in_executor(_fn) - # schedule_funding_job(service=service.hash) - # schedule_healthcheck_job(service=service.hash) - - # return JSONResponse( - # content=operate.service_manager().load_or_create(hash=service.hash).json - # ) - - # @app.put("/api/services") - # @with_retries - # async def _update_services(request: Request) -> JSONResponse: - # """Create a service.""" - # if operate.password is None: - # return USER_NOT_LOGGED_IN_ERROR - # template = await request.json() - # service = operate.service_manager().update_service( - # old_hash=template["old_service_hash"], - # new_hash=template["new_service_hash"], - # ) - # 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.fund_service(hash=service.hash) - - # # TODO Optimus patch, chain_id="10" - # chain_id = "10" - # manager.deploy_service_locally(hash=service.hash, chain_id=chain_id) - - # schedule_funding_job(service=service.hash) - # schedule_healthcheck_job(service=service.hash) - - # return JSONResponse(content=service.json) - - # TODO these endpoints below are possibly not used - - # @app.post("/api/services/{service}/onchain/deploy") - # @with_retries - # async def _deploy_and_run_service(request: Request) -> JSONResponse: - # """Create a service.""" - # if not operate.service_manager().exists(service=request.path_params["service"]): - # return service_not_found_error(service=request.path_params["service"]) - # if operate.password is None: - # return USER_NOT_LOGGED_IN_ERROR - # operate.service_manager().deploy_service_onchain( - # hash=request.path_params["service"] - # ) - # operate.service_manager().stake_service_on_chain( - # hash=request.path_params["service"] - # ) - # return JSONResponse( - # content=( - # operate.service_manager() - # .load_or_create(hash=request.path_params["service"]) - # .json - # ) - # ) - - # @app.post("/api/services/{service}/onchain/stop") - # @with_retries - # async def _stop_service_onchain(request: Request) -> JSONResponse: - # """Create a service.""" - # if not operate.service_manager().exists(service=request.path_params["service"]): - # return service_not_found_error(service=request.path_params["service"]) - # if operate.password is None: - # return USER_NOT_LOGGED_IN_ERROR - # operate.service_manager().terminate_service_on_chain( - # hash=request.path_params["service"] - # ) - # operate.service_manager().unbond_service_on_chain( - # hash=request.path_params["service"] - # ) - # operate.service_manager().unstake_service_on_chain( - # hash=request.path_params["service"] - # ) - # return JSONResponse( - # content=( - # operate.service_manager() - # .load_or_create(hash=request.path_params["service"]) - # .json - # ) - # ) - - # @app.post("/api/services/{service}/deployment/build") - # @with_retries - # async def _build_service_locally(request: Request) -> JSONResponse: - # """Create a service.""" - # # TODO: add support for chain id. - # if not operate.service_manager().exists(service=request.path_params["service"]): - # return service_not_found_error(service=request.path_params["service"]) - # deployment = ( - # operate.service_manager() - # .load_or_create( - # request.path_params["service"], - # ) - # .deployment - # ) - - # def _fn() -> None: - # deployment.build(force=True) - - # await run_in_executor(_fn) - # return JSONResponse(content=deployment.json) - - # @app.post("/api/services/{service}/deployment/start") - # @with_retries - # async def _start_service_locally(request: Request) -> JSONResponse: - # """Create a service.""" - # if not operate.service_manager().exists(service=request.path_params["service"]): - # return service_not_found_error(service=request.path_params["service"]) - # service = request.path_params["service"] - # manager = operate.service_manager() - - # def _fn() -> None: - # manager.deploy_service_onchain(hash=service) - # manager.stake_service_on_chain(hash=service) - # manager.fund_service(hash=service) - # manager.deploy_service_locally(hash=service, force=True) - - # await run_in_executor(_fn) - # schedule_funding_job(service=service) - # schedule_healthcheck_job(service=service.hash) - # return JSONResponse(content=manager.load_or_create(service).deployment) - - # @app.post("/api/services/{service}/deployment/stop") - # @with_retries - # async def _stop_service_locally(request: Request) -> JSONResponse: - # """Create a service.""" - # if not operate.service_manager().exists(service=request.path_params["service"]): - # return service_not_found_error(service=request.path_params["service"]) - # service = request.path_params["service"] - # deployment = operate.service_manager().load_or_create(service).deployment - # health_checker.stop_for_service(service=service) - - # await run_in_executor(deployment.stop) - # logger.info(f"Cancelling funding job for {service}") - # cancel_funding_job(service=service) - # return JSONResponse(content=deployment.json) - - # @app.post("/api/services/{service}/deployment/delete") - # @with_retries - # async def _delete_service_locally(request: Request) -> JSONResponse: - # """Create a service.""" - # if not operate.service_manager().exists(service=request.path_params["service"]): - # return service_not_found_error(service=request.path_params["service"]) - # # TODO: Drain safe before deleting service - # deployment = ( - # operate.service_manager() - # .load_or_create( - # request.path_params["service"], - # ) - # .deployment - # ) - # deployment.delete() - # return JSONResponse(content=deployment.json) - return app diff --git a/operate/services/manage.py b/operate/services/manage.py index 55e886c5c..70fab672d 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -1587,7 +1587,7 @@ def migrate_service_configs(self) -> None: ) if bafybei_count > 1: self.log_directories() - # raise RuntimeError(f"Your services folder contains {bafybei_count} folders starting with 'bafybei'. This is an unintended situation. Please contact support.") + raise RuntimeError(f"Your services folder contains {bafybei_count} folders starting with 'bafybei'. This is an unintended situation. Please contact support.") paths = list(self.path.iterdir()) for path in paths: diff --git a/operate/services/service.py b/operate/services/service.py index 76d833bd6..ae995653d 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -1010,9 +1010,12 @@ def consume_env_variables(self) -> None: def update_env_variables_values( self, env_var_to_value: t.Dict[str, str], except_if_undefined: bool = False ) -> None: - """Updates and stores the values of the env variables to override service.yaml on the deployment. + """ + Updates and stores the values of the env variables to override service.yaml on the deployment. + This method does not apply the variables to the environment. Use consume_env_variables to apply the - env variables.""" + env variables. + """ updated = False for var, value in env_var_to_value.items(): diff --git a/tox.ini b/tox.ini index 88426bd93..145b164b9 100644 --- a/tox.ini +++ b/tox.ini @@ -136,6 +136,7 @@ exclude=.md, packages/valory/protocols/contract_api, packages/valory/protocols/http, packages/valory/protocols/ledger_api + operate/data/ max-line-length = 88 select = B,C,D,E,F,I,W, ignore = E203,E501,W503,D202,B014,D400,D401,DAR,B028,B017 From 677e4d289414e8f8fbb153e4f6d08be2947a0aa0 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 22:04:16 +0100 Subject: [PATCH 187/463] fix: linters --- operate/ledger/profiles.py | 8 +++++--- operate/services/manage.py | 4 +++- operate/services/service.py | 11 ++++++----- operate/wallet/master.py | 4 ++-- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/operate/ledger/profiles.py b/operate/ledger/profiles.py index ad983acad..c1810de8c 100644 --- a/operate/ledger/profiles.py +++ b/operate/ledger/profiles.py @@ -19,10 +19,12 @@ """Chain profiles.""" +import typing as t + from operate.operate_types import ChainType, ContractAddresses -CONTRACTS = { +CONTRACTS: t.Dict[ChainType, ContractAddresses] = { ChainType.GNOSIS: ContractAddresses( { "service_manager": "0x04b0007b2aFb398015B76e5f22993a1fddF83644", @@ -75,7 +77,7 @@ ), } -STAKING = { +STAKING: t.Dict[ChainType, t.Dict[str, str]] = { ChainType.GNOSIS: { "pearl_alpha": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A", "pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d", @@ -95,7 +97,7 @@ }, } -OLAS = { +OLAS: t.Dict[ChainType, str] = { ChainType.GNOSIS: "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", ChainType.OPTIMISM: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527", ChainType.BASE: "0x54330d28ca3357F294334BDC454a032e7f353416", diff --git a/operate/services/manage.py b/operate/services/manage.py index 70fab672d..a15307455 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -1587,7 +1587,9 @@ def migrate_service_configs(self) -> None: ) if bafybei_count > 1: self.log_directories() - raise RuntimeError(f"Your services folder contains {bafybei_count} folders starting with 'bafybei'. This is an unintended situation. Please contact support.") + raise RuntimeError( + f"Your services folder contains {bafybei_count} folders starting with 'bafybei'. This is an unintended situation. Please contact support." + ) paths = list(self.path.iterdir()) for path in paths: diff --git a/operate/services/service.py b/operate/services/service.py index ae995653d..9685cc499 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -881,7 +881,7 @@ def service_public_id(self, include_version: bool = True) -> str: @staticmethod def get_service_public_id( - hash: str, dir: t.Optional[str] = None, include_version: bool = True + hash: str, temp_dir: t.Optional[Path] = None, include_version: bool = True ) -> str: """ Get the service public ID from IPFS based on the hash. @@ -891,7 +891,7 @@ def get_service_public_id( If None, a system-default temporary directory will be used. :return: The public ID of the service in the format "author/name:version". """ - with tempfile.TemporaryDirectory(dir=dir) as path: + with tempfile.TemporaryDirectory(dir=temp_dir) as path: package_path = Path( IPFSTool().download( hash_id=hash, @@ -1008,7 +1008,7 @@ def consume_env_variables(self) -> None: os.environ[env_var] = str(attributes["value"]) def update_env_variables_values( - self, env_var_to_value: t.Dict[str, str], except_if_undefined: bool = False + self, env_var_to_value: t.Dict[str, t.Any], except_if_undefined: bool = False ) -> None: """ Updates and stores the values of the env variables to override service.yaml on the deployment. @@ -1019,14 +1019,15 @@ def update_env_variables_values( updated = False for var, value in env_var_to_value.items(): + value_str = str(value) attributes = self.env_variables.get(var) if ( attributes and self.env_variables[var]["provision_type"] == ServiceEnvProvisionType.COMPUTED - and attributes["value"] != value + and attributes["value"] != value_str ): - attributes["value"] = str(value) + attributes["value"] = value_str updated = True elif except_if_undefined: raise ValueError( diff --git a/operate/wallet/master.py b/operate/wallet/master.py index e3ec758ef..672fa842c 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -53,7 +53,7 @@ class MasterWallet(LocalResource): """Master wallet.""" path: Path - safes: t.Optional[t.Dict[ChainType, str]] = {} + safes: t.Dict[ChainType, str] = {} safe_chains: t.List[ChainType] = [] ledger_type: LedgerType @@ -177,7 +177,7 @@ class EthereumMasterWallet(MasterWallet): path: Path address: str - safes: t.Optional[t.Dict[ChainType, str]] = field(default_factory=dict) # type: ignore + safes: t.Dict[ChainType, str] = field(default_factory=dict) # type: ignore safe_chains: t.List[ChainType] = field(default_factory=list) # type: ignore ledger_type: LedgerType = LedgerType.ETHEREUM safe_nonce: t.Optional[int] = None # For cross-chain reusability From 31a7f22083b33b55c83fffedc1ad7d40094c6a9c Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 22:27:11 +0100 Subject: [PATCH 188/463] fix: linters --- operate/services/manage.py | 4 ++-- operate/wallet/master.py | 4 ++-- tox.ini | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index a15307455..a20ff505d 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -498,7 +498,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to wallet = self.wallet_manager.load(ledger_config.type) sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) chain_type = ChainType.from_id(int(chain_id)) - safe = wallet.safes[chain_type] + safe = wallet.safes[chain_type] # type: ignore # TODO fix this os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc @@ -924,7 +924,7 @@ def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals instances = [key.address for key in keys] wallet = self.wallet_manager.load(ledger_config.type) chain_type = ChainType.from_id(int(chain_id)) - safe = wallet.safes[chain_type] + safe = wallet.safes[chain_type] # type: ignore # TODO fixme os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 672fa842c..e3ec758ef 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -53,7 +53,7 @@ class MasterWallet(LocalResource): """Master wallet.""" path: Path - safes: t.Dict[ChainType, str] = {} + safes: t.Optional[t.Dict[ChainType, str]] = {} safe_chains: t.List[ChainType] = [] ledger_type: LedgerType @@ -177,7 +177,7 @@ class EthereumMasterWallet(MasterWallet): path: Path address: str - safes: t.Dict[ChainType, str] = field(default_factory=dict) # type: ignore + safes: t.Optional[t.Dict[ChainType, str]] = field(default_factory=dict) # type: ignore safe_chains: t.List[ChainType] = field(default_factory=list) # type: ignore ledger_type: LedgerType = LedgerType.ETHEREUM safe_nonce: t.Optional[int] = None # For cross-chain reusability diff --git a/tox.ini b/tox.ini index 145b164b9..a4fd2bc84 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,7 @@ skip_install = True deps = tomte[black]==0.2.15 commands = - black operate scripts tests + black operate scripts tests --exclude operate/data [testenv:black-check] skipsdist = True @@ -27,7 +27,7 @@ skip_install = True deps = tomte[black]==0.2.15 commands = - black --check operate scripts tests + black --check operate scripts tests --exclude operate/data [testenv:isort] skipsdist = True From 800d972011fa3e0404e9b3400b16eae49f5a2053 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 13 Nov 2024 22:31:50 +0100 Subject: [PATCH 189/463] fix: linters --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index a4fd2bc84..259bb9ba8 100644 --- a/tox.ini +++ b/tox.ini @@ -35,7 +35,7 @@ skip_install = True deps = tomte[isort]==0.2.15 commands = - isort operate/ scripts/ tests/ + isort operate/ scripts/ tests/ --skip operate/data [testenv:isort-check] skipsdist = True @@ -43,7 +43,7 @@ skip_install = True deps = tomte[isort]==0.2.15 commands = - isort --check-only --gitignore operate/ scripts/ tests/ + isort --check-only --gitignore operate/ scripts/ tests/ --skip operate/data [testenv:flake8] skipsdist = True From 42517c39ec3566128f0b0382a7ac2a3e65994c4a Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 21:52:21 +0000 Subject: [PATCH 190/463] chore: remove old wallet type --- frontend/client/types.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 770eb4e82..7f09e8b9d 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -115,7 +115,7 @@ export type AppInfo = { }; }; -export type WalletResponse = { +export type MiddlewareWalletResponse = { address: Address; safe_chains: MiddlewareChain[]; ledger_type: MiddlewareLedger; @@ -124,9 +124,3 @@ export type WalletResponse = { }; safe_nonce: number; }; - -export type Wallet = WalletResponse & { - ethBalance?: number; - olasBalance?: number; - usdcBalance?: number; -}; From f362287956e93478cf1073816ff3cff15e2f2729 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 21:52:37 +0000 Subject: [PATCH 191/463] fix: use new wallet type --- frontend/context/WalletProvider.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/context/WalletProvider.tsx b/frontend/context/WalletProvider.tsx index e76c4b82e..13a33edca 100644 --- a/frontend/context/WalletProvider.tsx +++ b/frontend/context/WalletProvider.tsx @@ -7,7 +7,7 @@ import { } from 'react'; import { useInterval } from 'usehooks-ts'; -import { MiddlewareChain, Wallet } from '@/client'; +import { MiddlewareChain, MiddlewareWalletResponse } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { WalletService } from '@/service/Wallet'; import { Address } from '@/types/Address'; @@ -18,7 +18,7 @@ export const WalletContext = createContext<{ masterEoaAddress?: Address; masterSafeAddress?: Address; masterSafeAddresses?: Record; - wallets?: Wallet[]; + wallets?: MiddlewareWalletResponse[]; updateWallets: () => Promise; masterSafeAddressKeyExistsForChain: ( middlewareChain: MiddlewareChain, @@ -34,7 +34,7 @@ export const WalletContext = createContext<{ export const WalletProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); - const [wallets, setWallets] = useState(); + const [wallets, setWallets] = useState(); const masterEoaAddress: Address | undefined = wallets?.[0]?.address; const masterSafeAddress: Address | undefined = From e55609f463cc090342e4f0e8fe6bfea3d1aaaf9a Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 22:26:28 +0000 Subject: [PATCH 192/463] fix: optimize performance, moving logic out of context was a mistake --- frontend/context/ServicesProvider.tsx | 123 ++++++++++++++++---------- frontend/hooks/useService.ts | 2 +- frontend/hooks/useServices.ts | 49 +--------- 3 files changed, 81 insertions(+), 93 deletions(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index b1b67f5b4..ad5f7ab50 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -1,5 +1,5 @@ import { QueryObserverBaseResult, useQuery } from '@tanstack/react-query'; -import { noop } from 'lodash'; +import { isEmpty, noop } from 'lodash'; import { createContext, PropsWithChildren, @@ -13,6 +13,8 @@ import { import { MiddlewareServiceResponse } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { ChainId } from '@/enums/Chain'; +import { EoaWallet, SafeWallet, WalletOwner, WalletType } from '@/enums/Wallet'; import { UsePause, usePause } from '@/hooks/usePause'; import { ServicesService } from '@/service/Services'; import { Service } from '@/types/Service'; @@ -21,6 +23,8 @@ import { OnlineStatusContext } from './OnlineStatusProvider'; type ServicesContextType = { services?: MiddlewareServiceResponse[]; + serviceAddresses?: (SafeWallet | EoaWallet)[]; + servicesByChain?: Record; selectService: (serviceUuid: string) => void; selectedService?: Service; } & Partial> & @@ -61,14 +65,82 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { const selectedService = useMemo(() => { if (!services) return; return services.find( - (service) => service.service_config_id === selectedServiceUuid, + (service) => service.service_config_id === selectedServiceConfigId, ); - }, [selectedServiceUuid, services]); + }, [selectedServiceConfigId, services]); const selectService = useCallback((serviceUuid: string) => { setSelectedServiceConfigId(serviceUuid); }, []); + const servicesByChain = useMemo(() => { + if (!isFetched) return; + if (!services) return; + return Object.keys(ChainId).reduce( + ( + acc: Record, + chainIdKey: string, + ) => { + const chainIdNumber = +chainIdKey; + acc[chainIdNumber] = services.filter( + (service: MiddlewareServiceResponse) => + service.chain_configs[chainIdNumber], + ); + return acc; + }, + {}, + ); + }, [isFetched, services]); + + const serviceAddresses = useMemo(() => { + if (!isFetched) return; + if (isEmpty(services)) return []; + + return services?.reduce<(SafeWallet | EoaWallet)[]>( + (acc, service: MiddlewareServiceResponse) => { + return [ + ...acc, + ...Object.keys(service.chain_configs).reduce( + (acc: (SafeWallet | EoaWallet)[], chainIdKey: string) => { + const chainId = +chainIdKey; + const chainConfig = service.chain_configs[chainId]; + if (!chainConfig) return acc; + + const instances = chainConfig.chain_data.instances; + const multisig = chainConfig.chain_data.multisig; + + if (instances) { + acc.push( + ...instances.map( + (instance: string) => + ({ + address: instance, + type: WalletType.EOA, + owner: WalletOwner.Agent, + }) as EoaWallet, + ), + ); + } + + if (multisig) { + acc.push({ + address: multisig, + type: WalletType.Safe, + owner: WalletOwner.Agent, + chainId, + }); + } + + return acc; + }, + [], + ), + ]; + }, + [], + ); + }, [isFetched, services]); + /** * Select the first service by default */ @@ -80,59 +152,18 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { setSelectedServiceConfigId(services[0].service_config_id); }, [isFetched, selectedServiceConfigId, services]); - // const serviceAddresses = useMemo( - // () => - // services?.reduce((acc, service: MiddlewareServiceResponse) => { - // const instances = - // service.chain_configs[CHAINS.OPTIMISM.chainId].chain_data.instances; - // if (instances) { - // acc.push(...instances); - // } - - // const multisig = - // service.chain_configs[CHAINS.OPTIMISM.chainId].chain_data.multisig; - // if (multisig) { - // acc.push(multisig); - // } - // return acc; - // }, []), - // [services], - // ); - - // const updateServicesState = useCallback( - // async (): Promise => - // ServicesService.getServices() - // .then((data: MiddlewareServiceResponse[]) => { - // if (!Array.isArray(data)) return; - // setServices(data); - // setHasInitialLoaded(true); - // }) - // .catch((e) => { - // console.error(e); - // // message.error(e.message); Commented out to avoid showing error message; need to handle "isAuthenticated" in a better way - // }), - // [], - // ); - // const updateServiceStatus = useCallback(async () => { // if (!services?.[0]) return; // const serviceStatus = await ServicesService.getDeployment(services[0].service_config_id); // setServiceStatuses(serviceStatus.status); // }, [services]); - // Update service state - // useInterval( - // () => - // updateServicesState() - // .then(() => updateServiceStatus()) - // .catch((e) => message.error(e.message)), - // isOnline && !isPaused ? FIVE_SECONDS_INTERVAL : null, - // ); - return ( { - const { services, isLoaded } = useServices(); + const { services, isFetched: isLoaded } = useServices(); const queryClient = useQueryClient(); const service = useMemo(() => { diff --git a/frontend/hooks/useServices.ts b/frontend/hooks/useServices.ts index bfa11b851..47aa0b977 100644 --- a/frontend/hooks/useServices.ts +++ b/frontend/hooks/useServices.ts @@ -1,9 +1,8 @@ -import { useContext, useMemo } from 'react'; -import { useContext, useMemo } from 'react'; +import { useContext } from 'react'; -import { MiddlewareServiceResponse } from '@/client'; import { ServicesContext } from '@/context/ServicesProvider'; -import { ChainId } from '@/enums/Chain'; + +export const useServices = () => useContext(ServicesContext); // const checkServiceIsFundedOnChain = async ({ // service, @@ -78,45 +77,3 @@ import { ChainId } from '@/enums/Chain'; // return Object.values(fundRequirements).every((f) => f); // }; - -export const useServices = () => { - const { - services, - isFetched: isLoaded, - paused, - setPaused: setPaused, - selectedService, - selectService, - refetch, - } = useContext(ServicesContext); - - const servicesByChain = useMemo(() => { - if (!isLoaded) return; - if (!services) return; - return Object.keys(ChainId).reduce( - ( - acc: Record, - chainIdKey: string, - ) => { - const chainIdNumber = +chainIdKey; - acc[chainIdNumber] = services.filter( - (service: MiddlewareServiceResponse) => - service.chain_configs[chainIdNumber], - ); - return acc; - }, - {}, - ); - }, [isLoaded, services]); - - return { - services, - servicesByChain, - isLoaded, - setPaused, - paused, - selectedService, - selectService, - refetch, - }; -}; From ad70d41450b02677d8804094392fa69f67774808 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 22:27:03 +0000 Subject: [PATCH 193/463] chore: update useServices destructures --- .../MainPage/header/AgentButton/AgentNotRunningButton.tsx | 2 +- .../MainPage/header/AgentButton/AgentRunningButton.tsx | 2 +- .../ManageStakingPage/StakingContractSection/MigrateButton.tsx | 2 +- .../ManageStakingPage/StakingContractSection/useMigrate.tsx | 2 +- frontend/hooks/useLogs.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index e066a96cc..c60ecc60a 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -30,7 +30,7 @@ export const AgentNotRunningButton = () => { const { selectedService, setPaused: setIsServicePollingPaused, - isLoaded, + isFetched: isLoaded, refetch: updateServicesState, } = useServices(); diff --git a/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx index 1a33f2d7e..569b01cb1 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx @@ -32,7 +32,7 @@ export const AgentRunningButton = () => { const { showNotification } = useElectronApi(); const { isEligibleForRewards } = useReward(); - const { selectedService, isLoaded, setPaused } = useServices(); + const { selectedService, isFetched: isLoaded, setPaused } = useServices(); const { service, setDeploymentStatus } = useService({ serviceConfigId: diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index d2e03ed7a..97bdecbd1 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -32,7 +32,7 @@ export const MigrateButton = ({ const { serviceTemplate } = useServiceTemplates(); const { setPaused: setIsServicePollingPaused, - isLoaded: isServicesLoaded, + isFetched: isServicesLoaded, selectedService, } = useServices(); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index d411fad16..bc29e967a 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -60,7 +60,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { const { stakingContractInfo, hasEnoughServiceSlots } = useStakingContractInfo(stakingProgramId); - const { isLoaded: isServicesLoaded } = useServices(); + const { isFetched: isServicesLoaded } = useServices(); const { hasEnoughEthForInitialFunding } = useNeedsFunds(); diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index a6155dabb..de88bb930 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -48,7 +48,7 @@ const useBalancesLogs = () => { }; const useServicesLogs = () => { - const { services, isLoaded } = useServices(); + const { services, isFetched: isLoaded } = useServices(); const { getQueryData } = useQueryClient(); return { From ea79538644cc809fd257f98865da5a2b7c0d6f60 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 22:27:18 +0000 Subject: [PATCH 194/463] feat: add EoaWallet and SafeWallet types to Wallet enums --- frontend/enums/Wallet.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts index f6496c1d8..9e46bba4e 100644 --- a/frontend/enums/Wallet.ts +++ b/frontend/enums/Wallet.ts @@ -1,3 +1,7 @@ +import { Address } from '@/types/Address'; + +import { ChainId } from './Chain'; + export enum WalletType { Safe = 'multisig', EOA = 'eoa', @@ -7,3 +11,16 @@ export enum WalletOwner { Master = 'master', // user Agent = 'agent', } + +export type EoaWallet = { + address: Address; + type: WalletType.EOA; + owner: WalletOwner; +}; + +export type SafeWallet = { + address: Address; + type: WalletType.Safe; + owner: WalletOwner; + chainId: ChainId; +}; From 248a51abd77118e98ae9cbe244c73fd1fba67ab8 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 23:26:12 +0000 Subject: [PATCH 195/463] feat: add wallets key to react-query keys for wallet provider --- frontend/constants/react-query-keys.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index 1d5091714..a80ce53ec 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -1,5 +1,8 @@ export const REACT_QUERY_KEYS = { + // service provider SERVICES_KEY: ['services'] as const, SERVICE_DEPLOYMENT_STATUS_KEY: (serviceConfigId: string) => ['serviceStatus', serviceConfigId] as const, + // wallet provider + WALLETS_KEY: ['wallets'] as const, } as const; From 35ef9b9eb9b7d039bb892c2f65305a202ecaf18d Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 23:26:27 +0000 Subject: [PATCH 196/463] fix: comment out unused chain enums and add missing newline in EnvProvisionType --- frontend/client/enums.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index 4c01dd391..b61ab45b8 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -5,6 +5,7 @@ export enum MiddlewareAction { STOP = 3, } +/** commented unused chain enums as interferes with types */ export enum MiddlewareChain { ETHEREUM = 0, GOERLI = 1, @@ -38,7 +39,7 @@ export enum MiddlewareAccountIsSetup { } export enum EnvProvisionType { - FIXED = "fixed", - USER = "user", - COMPUTED = "computed" -} \ No newline at end of file + FIXED = 'fixed', + USER = 'user', + COMPUTED = 'computed', +} From eca63a3c2ca0721d65f2e7a29308b06a8145b9fe Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 23:27:51 +0000 Subject: [PATCH 197/463] fix: comment out unused MiddlewareChain enum to prevent type interference --- frontend/client/enums.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index b61ab45b8..73f05d2c0 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -5,7 +5,6 @@ export enum MiddlewareAction { STOP = 3, } -/** commented unused chain enums as interferes with types */ export enum MiddlewareChain { ETHEREUM = 0, GOERLI = 1, From e2dc0d0b0aa744a7abea8198f2ed96256c9a8ee5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 23:28:55 +0000 Subject: [PATCH 198/463] refactor: wallet provider, service, types, enums --- frontend/context/WalletProvider.tsx | 104 ++++++++++++++-------------- frontend/enums/Wallet.ts | 18 +++-- frontend/service/Wallet.ts | 4 +- 3 files changed, 69 insertions(+), 57 deletions(-) diff --git a/frontend/context/WalletProvider.tsx b/frontend/context/WalletProvider.tsx index 13a33edca..4ae8beb43 100644 --- a/frontend/context/WalletProvider.tsx +++ b/frontend/context/WalletProvider.tsx @@ -1,73 +1,75 @@ -import { - createContext, - PropsWithChildren, - useCallback, - useContext, - useState, -} from 'react'; -import { useInterval } from 'usehooks-ts'; +import { QueryObserverBaseResult, useQuery } from '@tanstack/react-query'; +import { createContext, PropsWithChildren, useContext, useState } from 'react'; -import { MiddlewareChain, MiddlewareWalletResponse } from '@/client'; +import { MiddlewareWalletResponse } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { + MasterEoa, + MasterSafe, + MasterWallets, + WalletOwner, + WalletType, +} from '@/enums/Wallet'; +import { UsePause } from '@/hooks/usePause'; import { WalletService } from '@/service/Wallet'; -import { Address } from '@/types/Address'; +import { convertMiddlewareChainToChainId } from '@/utils/middlewareHelpers'; import { OnlineStatusContext } from './OnlineStatusProvider'; -export const WalletContext = createContext<{ - masterEoaAddress?: Address; - masterSafeAddress?: Address; - masterSafeAddresses?: Record; - wallets?: MiddlewareWalletResponse[]; - updateWallets: () => Promise; - masterSafeAddressKeyExistsForChain: ( - middlewareChain: MiddlewareChain, - ) => boolean; -}>({ - masterEoaAddress: undefined, - masterSafeAddress: undefined, +type WalletContextType = { + wallets?: (MasterEoa | MasterSafe)[]; +} & Partial> & + UsePause; + +export const WalletContext = createContext({ wallets: undefined, - updateWallets: async () => {}, - masterSafeAddressKeyExistsForChain: () => false, + paused: false, + setPaused: () => {}, + togglePaused: () => {}, }); -export const WalletProvider = ({ children }: PropsWithChildren) => { - const { isOnline } = useContext(OnlineStatusContext); - - const [wallets, setWallets] = useState(); +const transformMiddlewareWalletResponse = ( + data: MiddlewareWalletResponse, +): MasterWallets => { + const masterEoa: MasterEoa = { + address: data.address, + owner: WalletOwner.Master, + type: WalletType.EOA, + }; - const masterEoaAddress: Address | undefined = wallets?.[0]?.address; - const masterSafeAddress: Address | undefined = - wallets?.[0]?.safes[MiddlewareChain.OPTIMISM]; + const masterSafes: MasterSafe[] = Object.entries(data.safes).map( + ([middlewareChain, address]) => ({ + address, + chainId: convertMiddlewareChainToChainId(+middlewareChain), + owner: WalletOwner.Master, + type: WalletType.Safe, + }), + ); - const masterSafeAddresses = wallets?.[0]?.safes; + return [masterEoa, ...masterSafes]; +}; - const masterSafeAddressKeyExistsForChain = useCallback( - (middlewareChain: MiddlewareChain) => - !!wallets?.[0]?.safes[middlewareChain], - [wallets], - ); +export const WalletProvider = ({ children }: PropsWithChildren) => { + const { isOnline } = useContext(OnlineStatusContext); - const updateWallets = async () => { - try { - const wallets = await WalletService.getWallets(); - setWallets(wallets); - } catch (e) { - console.error(e); - } - }; + const [paused, setPaused] = useState(false); - useInterval(updateWallets, isOnline ? FIVE_SECONDS_INTERVAL : null); + const { data: wallets, refetch } = useQuery({ + queryKey: REACT_QUERY_KEYS.WALLETS_KEY, + queryFn: WalletService.getWallets, + refetchInterval: isOnline && !paused ? FIVE_SECONDS_INTERVAL : false, + select: (data) => transformMiddlewareWalletResponse(data), + }); return ( setPaused((prev) => !prev), + refetch, }} > {children} diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts index 9e46bba4e..a75a7215b 100644 --- a/frontend/enums/Wallet.ts +++ b/frontend/enums/Wallet.ts @@ -6,21 +6,31 @@ export enum WalletType { Safe = 'multisig', EOA = 'eoa', } - export enum WalletOwner { Master = 'master', // user Agent = 'agent', } -export type EoaWallet = { +export type MasterEoa = { address: Address; type: WalletType.EOA; owner: WalletOwner; }; +export type MasterSafe = Omit & { + type: WalletType.Safe; + chainId: ChainId; +}; -export type SafeWallet = { +export type AgentEoa = { address: Address; + type: WalletType.EOA; + owner: WalletOwner.Agent; +}; + +export type AgentSafe = Omit & { type: WalletType.Safe; - owner: WalletOwner; chainId: ChainId; }; + +export type MasterWallets = (MasterEoa | MasterSafe)[]; +export type AgentWallets = (AgentEoa | AgentSafe)[]; diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index b9224ec9f..a1668f357 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -1,4 +1,4 @@ -import { MiddlewareChain, Wallet } from '@/client'; +import { MiddlewareChain, MiddlewareWalletResponse } from '@/client'; import { CONTENT_TYPE_JSON_UTF8 } from '@/constants/headers'; import { BACKEND_URL } from '@/constants/urls'; @@ -9,7 +9,7 @@ const getWallets = async () => fetch(`${BACKEND_URL}/wallet`).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to get wallets'); - }) as Promise; + }) as Promise; const createEoa = async (chain: MiddlewareChain) => fetch(`${BACKEND_URL}/wallet`, { From 823830756aea32b4c6b49e944af172000c7ee3f7 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 23:29:09 +0000 Subject: [PATCH 199/463] chore: update to use new types --- frontend/context/ServicesProvider.tsx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index ad5f7ab50..23c7dda76 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -14,7 +14,12 @@ import { MiddlewareServiceResponse } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { ChainId } from '@/enums/Chain'; -import { EoaWallet, SafeWallet, WalletOwner, WalletType } from '@/enums/Wallet'; +import { + AgentEoa, + AgentWallets, + WalletOwner, + WalletType, +} from '@/enums/Wallet'; import { UsePause, usePause } from '@/hooks/usePause'; import { ServicesService } from '@/service/Services'; import { Service } from '@/types/Service'; @@ -23,7 +28,7 @@ import { OnlineStatusContext } from './OnlineStatusProvider'; type ServicesContextType = { services?: MiddlewareServiceResponse[]; - serviceAddresses?: (SafeWallet | EoaWallet)[]; + serviceAddresses?: AgentWallets; servicesByChain?: Record; selectService: (serviceUuid: string) => void; selectedService?: Service; @@ -96,12 +101,12 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { if (!isFetched) return; if (isEmpty(services)) return []; - return services?.reduce<(SafeWallet | EoaWallet)[]>( + return services?.reduce( (acc, service: MiddlewareServiceResponse) => { return [ ...acc, ...Object.keys(service.chain_configs).reduce( - (acc: (SafeWallet | EoaWallet)[], chainIdKey: string) => { + (acc: AgentWallets, chainIdKey: string) => { const chainId = +chainIdKey; const chainConfig = service.chain_configs[chainId]; if (!chainConfig) return acc; @@ -117,7 +122,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { address: instance, type: WalletType.EOA, owner: WalletOwner.Agent, - }) as EoaWallet, + }) as AgentEoa, ), ); } From daa0b85bcd1a6f3433c98905272ad9b9e12d2f87 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 23:32:08 +0000 Subject: [PATCH 200/463] feat: middleware enum conversion helper --- frontend/utils/middlewareHelpers.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 frontend/utils/middlewareHelpers.ts diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts new file mode 100644 index 000000000..39fefab64 --- /dev/null +++ b/frontend/utils/middlewareHelpers.ts @@ -0,0 +1,24 @@ +import { MiddlewareChain } from '@/client'; +import { ChainId } from '@/enums/Chain'; + +/** + * Converts middleware chain enums to chain ids + * @param chain + * @returns ChainId + * @throws Error + */ +export const convertMiddlewareChainToChainId = ( + chain: MiddlewareChain, +): ChainId => { + switch (chain) { + case MiddlewareChain.ETHEREUM: + return ChainId.Ethereum; + case MiddlewareChain.OPTIMISM: + return ChainId.Optimism; + case MiddlewareChain.GNOSIS: + return ChainId.Gnosis; + case MiddlewareChain.BASE: + return ChainId.Base; + } + throw new Error(`Invalid middleware chain enum: ${chain}`); +}; From d24d98d18738e807555caaca525cf482f8e51bac Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 13 Nov 2024 23:32:19 +0000 Subject: [PATCH 201/463] feat: add Wallets type to encompass all wallet variations --- frontend/enums/Wallet.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts index a75a7215b..9d9ee2a1d 100644 --- a/frontend/enums/Wallet.ts +++ b/frontend/enums/Wallet.ts @@ -16,6 +16,7 @@ export type MasterEoa = { type: WalletType.EOA; owner: WalletOwner; }; + export type MasterSafe = Omit & { type: WalletType.Safe; chainId: ChainId; @@ -34,3 +35,4 @@ export type AgentSafe = Omit & { export type MasterWallets = (MasterEoa | MasterSafe)[]; export type AgentWallets = (AgentEoa | AgentSafe)[]; +export type Wallets = (MasterEoa | MasterSafe | AgentEoa | AgentSafe)[]; From a85e3cd60f3a85ff92e737d6cb1f0156573ac596 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 14 Nov 2024 10:13:38 +0000 Subject: [PATCH 202/463] fix: lint --- .../AgentButton/AgentNotRunningButton.tsx | 5 +++++ .../StakingContractSection/MigrateButton.tsx | 1 - frontend/context/BalanceProvider.tsx | 18 +++++++----------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index c60ecc60a..962bae7ce 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -217,7 +217,12 @@ export const AgentNotRunningButton = () => { return hasEnoughOlas && hasEnoughEth; }, [ + isStakingContractInfoRecordLoaded, deploymentStatus, + isLowBalance, + requiredOlas, + hasEnoughServiceSlots, + isServiceStaked, service, storeState?.isInitialFunded, isEligibleForStaking, diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index 97bdecbd1..d42465e91 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -3,7 +3,6 @@ import { isNil } from 'lodash'; import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; -import { ChainId } from '@/enums/Chain'; import { Pages } from '@/enums/Pages'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index c3fd0da45..746a42b81 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -1,4 +1,3 @@ -// TODO: large refactor needed, provider is way too big, needs to support multiple chains, multiple services, and multiple tokens import { message } from 'antd'; import { isAddress } from 'ethers/lib/utils'; import { isNil, isNumber } from 'lodash'; @@ -15,7 +14,7 @@ import { } from 'react'; import { useInterval } from 'usehooks-ts'; -import { Wallet } from '@/client'; +import { MiddlewareWalletResponse } from '@/client'; import { CHAIN_CONFIG } from '@/config/chains'; import { TOKEN_CONFIG } from '@/config/tokens'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; @@ -26,6 +25,8 @@ import { import { ChainId } from '@/enums/Chain'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { TokenSymbol } from '@/enums/Token'; +import { Wallets } from '@/enums/Wallet'; +import { useServices } from '@/hooks/useServices'; import { StakedAgentService } from '@/service/agents/StakedAgentService'; import { EthersService } from '@/service/Ethers'; import MulticallService from '@/service/Multicall'; @@ -37,7 +38,6 @@ import { import { OnlineStatusContext } from './OnlineStatusProvider'; import { RewardContext } from './RewardProvider'; -import { ServicesContext } from './ServicesProvider'; import { WalletContext } from './WalletProvider'; export const BalanceContext = createContext<{ @@ -51,16 +51,13 @@ export const BalanceContext = createContext<{ totalEthBalance?: number; totalOlasBalance?: number; isLowBalance: boolean; - wallets?: Wallet[]; + wallets?: Wallets[]; walletBalances: WalletAddressNumberRecord; agentSafeBalance?: ValueOf; agentEoaBalance?: ValueOf; updateBalances: () => Promise; setIsPaused: Dispatch>; totalOlasStakedBalance?: number; - baseBalance?: number; - ethereumBalance?: number; - optimismBalance?: number; }>({ isLoaded: false, setIsLoaded: () => {}, @@ -86,9 +83,8 @@ export const BalanceContext = createContext<{ export const BalanceProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); - const { wallets, masterEoaAddress, masterSafeAddress } = - useContext(WalletContext); - const { services } = useContext(ServicesContext); + const { wallets } = useContext(WalletContext); + const { services, serviceAddresses } = useServices(); const { optimisticRewardsEarnedForEpoch, accruedServiceStakingRewards } = useContext(RewardContext); @@ -348,7 +344,7 @@ export const getOlasBalances = async ( }; export const getWalletAddresses = ( - wallets: Wallet[], + wallets: MiddlewareWalletResponse[], serviceAddresses: Address[], ): Address[] => { const walletsToCheck: Address[] = []; From 34f8853998aa14ca816f93df689bcd504531b813 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 14 Nov 2024 10:16:09 +0000 Subject: [PATCH 203/463] chore: remove cast --- frontend/context/ServicesProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 23c7dda76..d0ff72dc2 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -122,7 +122,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { address: instance, type: WalletType.EOA, owner: WalletOwner.Agent, - }) as AgentEoa, + }), ), ); } From f17c0bddbed2186c3b5bdbd19806eedf4616dafc Mon Sep 17 00:00:00 2001 From: Mohan Date: Thu, 14 Nov 2024 15:48:01 +0530 Subject: [PATCH 204/463] feat update RewardProvider and related hooks (#448) * refactor: update staking rewards info retrieval to use AGENT_CONFIG * refactor: enhance RewardProvider to utilize react-query for rewards data fetching * refactor: update RewardProvider to use dynamic agent and chain selection for rewards fetching * refactor: update RewardProvider and react-query keys for dynamic rewards fetching * refactor: improve RewardProvider logic for storing first staking reward and refreshing rewards data * refactor: update StakingRewardsInfo to use Zod schema for validation and enhance query logic --- frontend/constants/react-query-keys.ts | 28 ++++ frontend/context/RewardProvider.tsx | 180 +++++++++++++++---------- frontend/types/Autonolas.ts | 26 ++-- 3 files changed, 155 insertions(+), 79 deletions(-) diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index 1d5091714..e2772581c 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -2,4 +2,32 @@ export const REACT_QUERY_KEYS = { SERVICES_KEY: ['services'] as const, SERVICE_DEPLOYMENT_STATUS_KEY: (serviceConfigId: string) => ['serviceStatus', serviceConfigId] as const, + REWARDS_KEY: ( + chainId: number, + serviceUuid: string, + stakingProgramId: string, + multisig: string, + token: number, + ) => + [ + 'rewards', + chainId, + serviceUuid, + stakingProgramId, + multisig, + token, + ] as const, + AVAILABLE_REWARDS_FOR_EPOCH_KEY: ( + currentChainId: number, + serviceConfigId: string, + stakingProgramId: string, + chainId: number, + ) => + [ + 'availableRewardsForEpoch', + currentChainId, + serviceConfigId, + stakingProgramId, + chainId, + ] as const, } as const; diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index d409ae037..d3327ddd7 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -1,4 +1,5 @@ -import { ethers } from 'ethers'; +import { useQuery } from '@tanstack/react-query'; +import { formatUnits } from 'ethers/lib/utils'; import { createContext, PropsWithChildren, @@ -6,18 +7,19 @@ import { useContext, useEffect, useMemo, - useState, } from 'react'; -import { useInterval } from 'usehooks-ts'; -import { CHAIN_CONFIG } from '@/config/chains'; +import { AGENT_CONFIG } from '@/config/agents'; +import { GNOSIS_CHAIN_CONFIG } from '@/config/chains'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { useElectronApi } from '@/hooks/useElectronApi'; +import { useService } from '@/hooks/useService'; +import { useServices } from '@/hooks/useServices'; import { useStore } from '@/hooks/useStore'; -import { AutonolasService } from '@/service/Autonolas'; +import { StakingRewardsInfoSchema } from '@/types/Autonolas'; import { OnlineStatusContext } from './OnlineStatusProvider'; -import { ServicesContext } from './ServicesProvider'; import { StakingProgramContext } from './StakingProgramProvider'; export const RewardContext = createContext<{ @@ -38,88 +40,130 @@ export const RewardContext = createContext<{ updateRewards: async () => {}, }); -export const RewardProvider = ({ children }: PropsWithChildren) => { +const currentAgent = AGENT_CONFIG.trader; // TODO: replace with dynamic agent selection +const currentChainId = GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with dynamic chain selection + +/** + * hook to fetch staking rewards details + */ +const useStakingRewardsDetails = () => { + const { isOnline } = useContext(OnlineStatusContext); + const { activeStakingProgramId } = useContext(StakingProgramContext); + + const { selectedService, isLoaded } = useServices(); + const serviceConfigId = + isLoaded && selectedService ? selectedService?.service_config_id : ''; + const { service } = useService({ serviceConfigId }); + + // fetch chain data from the selected service + const chainData = service?.chain_configs[currentChainId].chain_data; + const multisig = chainData?.multisig; + const token = chainData?.token; + + return useQuery({ + queryKey: REACT_QUERY_KEYS.REWARDS_KEY( + currentChainId, + serviceConfigId, + activeStakingProgramId!, + multisig!, + token!, + ), + queryFn: async () => { + const response = await currentAgent.serviceApi.getAgentStakingRewardsInfo( + { + agentMultisigAddress: multisig!, + serviceId: token!, + stakingProgramId: activeStakingProgramId!, + chainId: currentChainId, + }, + ); + return StakingRewardsInfoSchema.parse(response); + }, + enabled: !!isOnline && !!activeStakingProgramId && !!multisig && !!token, + refetchInterval: isOnline ? FIVE_SECONDS_INTERVAL : false, + refetchOnWindowFocus: false, + }); +}; + +/** + * hook to fetch available rewards for the current epoch + */ +const useAvailableRewardsForEpoch = () => { const { isOnline } = useContext(OnlineStatusContext); - const { services } = useContext(ServicesContext); - const service = useMemo(() => services?.[0], [services]); - const { storeState } = useStore(); - const electronApi = useElectronApi(); const { activeStakingProgramId, defaultStakingProgramId } = useContext( StakingProgramContext, ); + const { selectedService, isLoaded } = useServices(); + const serviceConfigId = + isLoaded && selectedService ? selectedService?.service_config_id : ''; + + return useQuery({ + queryKey: REACT_QUERY_KEYS.AVAILABLE_REWARDS_FOR_EPOCH_KEY( + currentChainId, + serviceConfigId, + activeStakingProgramId!, + currentChainId, + ), + queryFn: async () => { + return await currentAgent.serviceApi.getAvailableRewardsForEpoch( + activeStakingProgramId ?? defaultStakingProgramId, + currentChainId, + ); + }, + enabled: + !!isOnline && !!activeStakingProgramId && !!defaultStakingProgramId, + refetchInterval: isOnline ? FIVE_SECONDS_INTERVAL : false, + refetchOnWindowFocus: false, + }); +}; - const [accruedServiceStakingRewards, setAccruedServiceStakingRewards] = - useState(); - const [availableRewardsForEpoch, setAvailableRewardsForEpoch] = - useState(); - const [isEligibleForRewards, setIsEligibleForRewards] = useState(); +/** + * Provider to manage rewards context + */ +export const RewardProvider = ({ children }: PropsWithChildren) => { + const { storeState } = useStore(); + const electronApi = useElectronApi(); - const availableRewardsForEpochEth = useMemo(() => { - if (!availableRewardsForEpoch) return; + const { data: stakingRewardsDetails, refetch: refetchStakingRewardsDetails } = + useStakingRewardsDetails(); + const { + data: availableRewardsForEpoch, + refetch: refetchAvailableRewardsForEpoch, + } = useAvailableRewardsForEpoch(); - const formatRewardsEth = parseFloat( - ethers.utils.formatUnits(`${availableRewardsForEpoch}`, 18), - ); + const isEligibleForRewards = stakingRewardsDetails?.isEligibleForRewards; + const accruedServiceStakingRewards = + stakingRewardsDetails?.accruedServiceStakingRewards; - return formatRewardsEth; + // available rewards for the current epoch in ETH + const availableRewardsForEpochEth = useMemo(() => { + if (!availableRewardsForEpoch) return; + return parseFloat(formatUnits(`${availableRewardsForEpoch}`)); }, [availableRewardsForEpoch]); + // optimistic rewards earned for the current epoch in ETH const optimisticRewardsEarnedForEpoch = useMemo(() => { - if (isEligibleForRewards && availableRewardsForEpochEth) { - return availableRewardsForEpochEth; - } - return; + if (!isEligibleForRewards) return; + if (!availableRewardsForEpochEth) return; + return availableRewardsForEpochEth; }, [availableRewardsForEpochEth, isEligibleForRewards]); - const updateRewards = useCallback(async (): Promise => { - let stakingRewardsInfoPromise; - - // only check for rewards if there's a currentStakingProgram active - if ( - activeStakingProgramId && - service?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.multisig && - service?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.token - ) { - stakingRewardsInfoPromise = AutonolasService.getAgentStakingRewardsInfo({ - agentMultisigAddress: - service.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data.multisig!, - serviceId: - service.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data.token!, - stakingProgram: activeStakingProgramId, - }); - } - - // can fallback to default staking program if no current staking program is active - const epochRewardsPromise = AutonolasService.getAvailableRewardsForEpoch( - activeStakingProgramId ?? defaultStakingProgramId, - ); - - const [stakingRewardsInfo, rewards] = await Promise.all([ - stakingRewardsInfoPromise, - epochRewardsPromise, - ]); - - setIsEligibleForRewards(stakingRewardsInfo?.isEligibleForRewards); - setAccruedServiceStakingRewards( - stakingRewardsInfo?.accruedServiceStakingRewards, - ); - setAvailableRewardsForEpoch(rewards); - }, [activeStakingProgramId, defaultStakingProgramId, service]); - + // store the first staking reward achieved in the store for notification useEffect(() => { - if (isEligibleForRewards && !storeState?.firstStakingRewardAchieved) { - electronApi.store?.set?.('firstStakingRewardAchieved', true); - } + if (!isEligibleForRewards) return; + if (storeState?.firstStakingRewardAchieved) return; + electronApi.store?.set?.('firstStakingRewardAchieved', true); }, [ electronApi.store, isEligibleForRewards, storeState?.firstStakingRewardAchieved, ]); - useInterval( - async () => updateRewards(), - isOnline ? FIVE_SECONDS_INTERVAL : null, - ); + // refresh rewards data + const updateRewards = useCallback(async () => { + await refetchStakingRewardsDetails(); + await refetchAvailableRewardsForEpoch(); + }, [refetchStakingRewardsDetails, refetchAvailableRewardsForEpoch]); return ( ; export type StakingContractInfo = { availableRewards: number; From 018e07526936593f7e56936dbc5cf1001d7a03f0 Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Thu, 14 Nov 2024 02:58:49 +0530 Subject: [PATCH 205/463] Refactor: ChainType and LedgerType Signed-off-by: OjusWiZard --- api.md | 18 +-- frontend/client/enums.ts | 14 +- frontend/client/types.ts | 2 +- .../SetupPage/Create/SetupCreateSafe.tsx | 14 +- .../SetupPage/Create/SetupEoaFunding.tsx | 6 +- .../components/YourWalletPage/YourAgent.tsx | 2 +- frontend/config/chains.ts | 2 +- frontend/constants/serviceTemplates.ts | 13 +- frontend/hooks/useNeedsFunds.ts | 3 +- frontend/service/Services.ts | 8 +- operate/cli.py | 33 ++-- operate/ledger/__init__.py | 80 ++++------ operate/ledger/profiles.py | 38 ++--- operate/operate_types.py | 108 +++++++------- operate/resource.py | 4 +- operate/services/manage.py | 141 ++++++++---------- operate/services/protocol.py | 12 +- operate/services/service.py | 64 +++++--- operate/wallet/master.py | 99 +++++++----- scripts/setup_wallet.py | 6 +- templates/optimus.yaml | 8 +- templates/trader.yaml | 4 +- 22 files changed, 353 insertions(+), 326 deletions(-) diff --git a/api.md b/api.md index 4ed49d22b..60eac290d 100644 --- a/api.md +++ b/api.md @@ -295,7 +295,7 @@ Returns the list of existing service configurations. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, - "home_chain_id": "100", + "home_chain": "100", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -324,7 +324,7 @@ Create a service configuration using a template. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", - "home_chain_id": "100", + "home_chain": "100", "name": "valory/trader_omen_gnosis", "service_version": "v0.18.4" } @@ -342,7 +342,7 @@ Create a service configuration using a template. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, - "home_chain_id": "100", + "home_chain": "100", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -369,7 +369,7 @@ Update all the service configurations whose Service Public ID match the Service "env_variables": {...}, "hash": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me", "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", - "home_chain_id": "100", + "home_chain": "100", "name": "valory/trader_omen_gnosis", "service_version": "v0.19.0" } @@ -390,7 +390,7 @@ The response contains an array of the services which have been updated (an empty "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "1731490000": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me"}, - "home_chain_id": "100", + "home_chain": "100", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -451,7 +451,7 @@ Returns the service configuration `service_config_id`. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, - "home_chain_id": "100", + "home_chain": "100", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -498,7 +498,7 @@ The response contains the updated service configuration following the on-chain o "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, - "home_chain_id": "100", + "home_chain": "100", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -525,7 +525,7 @@ Update service configuration `service_config_id` with the provided template. "env_variables": {...}, "hash": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me", "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", - "home_chain_id": "100", + "home_chain": "100", "name": "valory/trader_omen_gnosis", "service_version": "v0.19.0" } @@ -545,7 +545,7 @@ Update service configuration `service_config_id` with the provided template. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "1731490000": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me"}, - "home_chain_id": "100", + "home_chain": "100", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index 4c01dd391..e6e6316c0 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -6,13 +6,13 @@ export enum MiddlewareAction { } export enum MiddlewareChain { - ETHEREUM = 0, - GOERLI = 1, - GNOSIS = 2, - SOLANA = 3, - OPTIMISM = 4, - BASE = 5, - MODE = 6, + ETHEREUM = "ethereum", + GOERLI = "goerli", + GNOSIS = "gnosis", + SOLANA = "solana", + OPTIMISM = "optimism", + BASE = "base", + MODE = "mode", } export enum MiddlewareLedger { diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 770eb4e82..3533237c3 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -75,7 +75,7 @@ export type ServiceTemplate = { description: string; image: string; service_version: string; - home_chain_id: string; + home_chain: string; configurations: { [key: string]: ConfigurationTemplate }; env_variables: { [key: string]: EnvVariableAttributes }; deploy?: boolean; diff --git a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx index 01988a141..caaefe088 100644 --- a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx +++ b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx @@ -16,10 +16,14 @@ import { delayInSeconds } from '@/utils/delay'; const { Text } = Typography; -const capitalizedMiddlewareChainNames = { - [+MiddlewareChain.ETHEREUM]: 'Ethereum', - [+MiddlewareChain.BASE]: 'Base', - [+MiddlewareChain.OPTIMISM]: 'Optimism', +const capitalizedMiddlewareChainNames: { [key in MiddlewareChain]: string } = { + [MiddlewareChain.ETHEREUM]: 'Ethereum', + [MiddlewareChain.BASE]: 'Base', + [MiddlewareChain.OPTIMISM]: 'Optimism', + [MiddlewareChain.GOERLI]: 'Goerli', + [MiddlewareChain.GNOSIS]: 'Gnosis', + [MiddlewareChain.SOLANA]: 'Solana', + [MiddlewareChain.MODE]: 'Mode', }; export const SetupCreateSafe = () => { @@ -129,7 +133,7 @@ export const SetupCreateSafe = () => { const safeCreationsRequired = Object.entries(chainsToCreateSafesFor).reduce( (acc, [chain, safeAddressAlreadyExists]) => { - const middlewareChain = +chain as MiddlewareChain; + const middlewareChain = chain as MiddlewareChain; if (safeAddressAlreadyExists) { switch (middlewareChain) { case MiddlewareChain.OPTIMISM: diff --git a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx index 9b566ca37..721552d32 100644 --- a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx +++ b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx @@ -173,11 +173,11 @@ export const SetupEoaFunding = () => { const { goto } = useSetup(); const { masterEoaAddress } = useWallet(); const [currentChain, setCurrentChain] = useState( - +Object.keys(eoaFundingMap)[0] as MiddlewareChain, + Object.keys(eoaFundingMap)[0] as MiddlewareChain, ); const currentFundingMapObject = - eoaFundingMap[+currentChain as keyof typeof eoaFundingMap]; + eoaFundingMap[currentChain as keyof typeof eoaFundingMap]; const getIsCurrentChainFunded = useCallback( async ( @@ -218,7 +218,7 @@ export const SetupEoaFunding = () => { if (nextChainExists) { // goto next chain setCurrentChain( - +Object.keys(eoaFundingMap)[indexOfCurrentChain + 1] as MiddlewareChain, + Object.keys(eoaFundingMap)[indexOfCurrentChain + 1] as MiddlewareChain, ); return; } diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index 8155d6bd2..cbec11632 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -109,7 +109,7 @@ const AgentTitle = () => { const ServiceAndNftDetails = () => { const { serviceId } = useServices(); const serviceAddress = - SERVICE_REGISTRY_L2_CONTRACT_ADDRESS[`${MiddlewareChain.OPTIMISM}`]; + SERVICE_REGISTRY_L2_CONTRACT_ADDRESS[MiddlewareChain.OPTIMISM]; return ( diff --git a/frontend/config/chains.ts b/frontend/config/chains.ts index 3e3188142..a38fc47f3 100644 --- a/frontend/config/chains.ts +++ b/frontend/config/chains.ts @@ -12,7 +12,7 @@ type ChainConfig = { name: string; currency: string; chainId: number; - middlewareChain: number; + middlewareChain: MiddlewareChainId; rpc: HttpUrl; }; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 1204df060..0b500f71f 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -1,4 +1,5 @@ import { ServiceTemplate, EnvProvisionType } from '@/client'; +import { CHAIN_CONFIG } from '@/config/chains'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; @@ -10,9 +11,9 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ image: 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', service_version: 'v0.18.4', - home_chain_id: ChainId.Gnosis.toString(), + home_chain: CHAIN_CONFIG[ChainId.Gnosis].middlewareChain, configurations: { - [ChainId.Optimism]: { + [CHAIN_CONFIG[ChainId.Optimism].middlewareChain]: { staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', rpc: 'http://localhost:8545', @@ -105,9 +106,9 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ // image: // 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', // service_version: 'v0.2.9', - // home_chain_id: `${CHAINS.OPTIMISM.chainId}`, + // home_chain: `${CHAINS.OPTIMISM}`, // configurations: { - // [CHAINS.OPTIMISM.chainId]: { + // [CHAINS.OPTIMISM.middlewareChain]: { // staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten // nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', // // rpc: 'http://localhost:8545', @@ -122,7 +123,7 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ // safe: 1000, // }, // }, - // [CHAINS.ETHEREUM.chainId]: { + // [CHAINS.ETHEREUM.middlewareChain]: { // staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten // nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', // // rpc: 'http://localhost:8545', @@ -137,7 +138,7 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ // safe: 1000, // }, // }, - // [CHAINS.BASE.chainId]: { + // [CHAINS.BASE.middlewareChain]: { // staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten // nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', // // rpc: 'http://localhost:8545', diff --git a/frontend/hooks/useNeedsFunds.ts b/frontend/hooks/useNeedsFunds.ts index 6898ea776..4219897a5 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -6,6 +6,7 @@ import { CHAIN_CONFIG } from '@/config/chains'; import { useBalance } from './useBalance'; import { useServiceTemplates } from './useServiceTemplates'; import { useStore } from './useStore'; +import { ChainId } from '@/enums/Chain'; export const useNeedsFunds = () => { const { getServiceTemplates } = useServiceTemplates(); @@ -26,7 +27,7 @@ export const useNeedsFunds = () => { const serviceFundRequirements = useMemo(() => { const gasEstimate = - serviceTemplate.configurations[CHAIN_CONFIG.OPTIMISM.chainId] + serviceTemplate.configurations[CHAIN_CONFIG[ChainId.Optimism].middlewareChain] .monthly_gas_estimate; const monthlyGasEstimate = Number(formatUnits(`${gasEstimate}`, 18)); const minimumStakedAmountRequired = diff --git a/frontend/service/Services.ts b/frontend/service/Services.ts index a80189c77..686aa31b2 100644 --- a/frontend/service/Services.ts +++ b/frontend/service/Services.ts @@ -67,8 +67,8 @@ const createService = async ({ ...serviceTemplate, deploy, configurations: { - [chainId]: { - ...serviceTemplate.configurations[ChainId.Optimism], + [CHAIN_CONFIG[chainId].middlewareChain]: { + ...serviceTemplate.configurations[CHAIN_CONFIG[chainId].middlewareChain], staking_program_id: stakingProgramId, rpc: CHAIN_CONFIG[chainId].rpc, use_mech_marketplace: useMechMarketplace, @@ -109,8 +109,8 @@ const updateService = async ({ ...serviceTemplate, deploy, configurations: { - [chainId]: { - ...serviceTemplate.configurations[ChainId.Optimism], + [CHAIN_CONFIG[chainId].middlewareChain]: { + ...serviceTemplate.configurations[CHAIN_CONFIG[chainId].middlewareChain], staking_program_id: stakingProgramId, rpc: CHAIN_CONFIG[chainId].rpc, use_mech_marketplace: useMechMarketplace, diff --git a/operate/cli.py b/operate/cli.py index cf5ac7639..91a7b6407 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -42,8 +42,7 @@ from operate import services from operate.account.user import UserAccount from operate.constants import KEY, KEYS, OPERATE, SERVICES -from operate.ledger import get_ledger_type_from_chain_type -from operate.operate_types import ChainType, DeploymentStatus +from operate.operate_types import Chain, DeploymentStatus from operate.services.health_checker import HealthChecker from operate.wallet.master import MasterWalletManager @@ -408,9 +407,7 @@ async def _get_wallets(request: Request) -> t.List[t.Dict]: @with_retries async def _get_wallet_by_chain(request: Request) -> t.List[t.Dict]: """Create wallet safe""" - ledger_type = get_ledger_type_from_chain_type( - chain=ChainType.from_string(request.path_params["chain"]) - ) + ledger_type = Chain.from_string(request.path_params["chain"]).ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse( @@ -438,8 +435,8 @@ async def _create_wallet(request: Request) -> t.List[t.Dict]: ) data = await request.json() - chain_type = ChainType(data["chain_type"]) - ledger_type = get_ledger_type_from_chain_type(chain=chain_type) + chain_type = Chain(data["chain_type"]) + ledger_type = chain_type.ledger_type manager = operate.wallet_manager if manager.exists(ledger_type=ledger_type): return JSONResponse( @@ -467,8 +464,8 @@ async def _get_safes(request: Request) -> t.List[t.Dict]: @with_retries async def _get_safe(request: Request) -> t.List[t.Dict]: """Create wallet safe""" - chain_type = ChainType.from_string(request.path_params["chain"]) - ledger_type = get_ledger_type_from_chain_type(chain=chain_type) + chain_type = Chain.from_string(request.path_params["chain"]) + ledger_type = chain_type.ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse( @@ -502,8 +499,8 @@ async def _create_safe(request: Request) -> t.List[t.Dict]: ) data = await request.json() - chain_type = ChainType(data["chain_type"]) - ledger_type = get_ledger_type_from_chain_type(chain=chain_type) + chain_type = Chain(data["chain_type"]) + ledger_type = chain_type.ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse(content={"error": "Wallet does not exist"}) @@ -517,7 +514,7 @@ async def _create_safe(request: Request) -> t.List[t.Dict]: } ) - safes = t.cast(t.Dict[ChainType, str], wallet.safes) + safes = t.cast(t.Dict[Chain, str], wallet.safes) wallet.create_safe( # pylint: disable=no-member chain_type=chain_type, owner=data.get("owner"), @@ -549,10 +546,10 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: ) data = await request.json() - chain_types = [ChainType(chain_type) for chain_type in data["chain_types"]] + chain_types = [Chain(chain_type) for chain_type in data["chain_types"]] # check that all chains are supported for chain_type in chain_types: - ledger_type = get_ledger_type_from_chain_type(chain=chain_type) + ledger_type = chain_type.ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse( @@ -563,7 +560,7 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: # mint the safes for chain_type in chain_types: - ledger_type = get_ledger_type_from_chain_type(chain=chain_type) + ledger_type = chain_type.ledger_type manager = operate.wallet_manager wallet = manager.load(ledger_type=ledger_type) @@ -571,7 +568,7 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: logger.info(f"Safe already exists for chain_type {chain_type}") continue - safes = t.cast(t.Dict[ChainType, str], wallet.safes) + safes = t.cast(t.Dict[Chain, str], wallet.safes) wallet.create_safe( # pylint: disable=no-member chain_type=chain_type, owner=data.get("owner"), @@ -603,8 +600,8 @@ async def _update_safe(request: Request) -> t.List[t.Dict]: ) data = await request.json() - chain_type = ChainType(data["chain_type"]) - ledger_type = get_ledger_type_from_chain_type(chain=chain_type) + chain_type = Chain(data["chain_type"]) + ledger_type = chain_type.ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse(content={"error": "Wallet does not exist"}) diff --git a/operate/ledger/__init__.py b/operate/ledger/__init__.py index 7238257f8..76cbf0125 100644 --- a/operate/ledger/__init__.py +++ b/operate/ledger/__init__.py @@ -25,7 +25,7 @@ from operate.ledger.base import LedgerHelper from operate.ledger.ethereum import Ethereum from operate.ledger.solana import Solana -from operate.operate_types import ChainType, LedgerType +from operate.operate_types import Chain, LedgerType ETHEREUM_PUBLIC_RPC = os.environ.get( @@ -55,33 +55,33 @@ MODE_RPC = os.environ.get("MODE_DEV_RPC", "https://rpc.mode.network") PUBLIC_RPCS = { - ChainType.ETHEREUM: ETHEREUM_PUBLIC_RPC, - ChainType.GNOSIS: GNOSIS_PUBLIC_RPC, - ChainType.GOERLI: GOERLI_PUBLIC_RPC, - ChainType.SOLANA: SOLANA_PUBLIC_RPC, - ChainType.BASE: BASE_PUBLIC_RPC, - ChainType.OPTIMISM: OPTIMISM_PUBLIC_RPC, - ChainType.MODE: MODE_PUBLIC_RPC, + Chain.ETHEREUM: ETHEREUM_PUBLIC_RPC, + Chain.GNOSIS: GNOSIS_PUBLIC_RPC, + Chain.GOERLI: GOERLI_PUBLIC_RPC, + Chain.SOLANA: SOLANA_PUBLIC_RPC, + Chain.BASE: BASE_PUBLIC_RPC, + Chain.OPTIMISTIC: OPTIMISM_PUBLIC_RPC, + Chain.MODE: MODE_PUBLIC_RPC, } DEFAULT_RPCS = { - ChainType.ETHEREUM: ETHEREUM_RPC, - ChainType.GNOSIS: GNOSIS_RPC, - ChainType.GOERLI: GOERLI_RPC, - ChainType.SOLANA: SOLANA_RPC, - ChainType.BASE: BASE_RPC, - ChainType.OPTIMISM: OPTIMISM_RPC, - ChainType.MODE: MODE_RPC, + Chain.ETHEREUM: ETHEREUM_RPC, + Chain.GNOSIS: GNOSIS_RPC, + Chain.GOERLI: GOERLI_RPC, + Chain.SOLANA: SOLANA_RPC, + Chain.BASE: BASE_RPC, + Chain.OPTIMISTIC: OPTIMISM_RPC, + Chain.MODE: MODE_RPC, } -CHAIN_HELPERS: t.Dict[ChainType, t.Type[LedgerHelper]] = { - ChainType.ETHEREUM: Ethereum, - ChainType.GNOSIS: Ethereum, - ChainType.GOERLI: Ethereum, - ChainType.SOLANA: Solana, - ChainType.BASE: Ethereum, - ChainType.OPTIMISM: Ethereum, - ChainType.MODE: Ethereum, +CHAIN_HELPERS: t.Dict[Chain, t.Type[LedgerHelper]] = { + Chain.ETHEREUM: Ethereum, + Chain.GNOSIS: Ethereum, + Chain.GOERLI: Ethereum, + Chain.SOLANA: Solana, + Chain.BASE: Ethereum, + Chain.OPTIMISTIC: Ethereum, + Chain.MODE: Ethereum, } LEDGER_HELPERS: t.Dict[LedgerType, t.Type[LedgerHelper]] = { @@ -90,36 +90,22 @@ } CURRENCY_DENOMS = { - ChainType.ETHEREUM: "Wei", - ChainType.GNOSIS: "xDai", - ChainType.GOERLI: "GWei", - ChainType.SOLANA: "Lamp", - ChainType.BASE: "Wei", - ChainType.OPTIMISM: "Wei", - ChainType.MODE: "Wei", + Chain.ETHEREUM: "Wei", + Chain.GNOSIS: "xDai", + Chain.GOERLI: "GWei", + Chain.SOLANA: "Lamp", + Chain.BASE: "Wei", + Chain.OPTIMISTIC: "Wei", + Chain.MODE: "Wei", } -def get_default_rpc(chain: ChainType) -> str: +def get_default_rpc(chain: Chain) -> str: """Get default RPC chain type.""" return DEFAULT_RPCS.get(chain, ETHEREUM_RPC) -def get_ledger_type_from_chain_type(chain: ChainType) -> LedgerType: - """Get LedgerType from ChainType.""" - if chain in ( - ChainType.ETHEREUM, - ChainType.GOERLI, - ChainType.GNOSIS, - ChainType.BASE, - ChainType.OPTIMISM, - ChainType.MODE, - ): - return LedgerType.ETHEREUM - return LedgerType.SOLANA - - -def get_ledger_helper_by_chain(rpc: str, chain: ChainType) -> LedgerHelper: +def get_ledger_helper_by_chain(rpc: str, chain: Chain) -> LedgerHelper: """Get ledger helper by chain type.""" return CHAIN_HELPERS.get(chain, Ethereum)(rpc=rpc) @@ -129,6 +115,6 @@ def get_ledger_helper_by_ledger(rpc: str, ledger: LedgerHelper) -> LedgerHelper: return LEDGER_HELPERS.get(ledger, Ethereum)(rpc=rpc) # type: ignore -def get_currency_denom(chain: ChainType) -> str: +def get_currency_denom(chain: Chain) -> str: """Get currency denom by chain type.""" return CURRENCY_DENOMS.get(chain, "Wei") diff --git a/operate/ledger/profiles.py b/operate/ledger/profiles.py index c1810de8c..9d15b8663 100644 --- a/operate/ledger/profiles.py +++ b/operate/ledger/profiles.py @@ -21,11 +21,11 @@ import typing as t -from operate.operate_types import ChainType, ContractAddresses +from operate.operate_types import Chain, ContractAddresses -CONTRACTS: t.Dict[ChainType, ContractAddresses] = { - ChainType.GNOSIS: ContractAddresses( +CONTRACTS: t.Dict[Chain, ContractAddresses] = { + Chain.GNOSIS: ContractAddresses( { "service_manager": "0x04b0007b2aFb398015B76e5f22993a1fddF83644", "service_registry": "0x9338b5153AE39BB89f50468E608eD9d764B755fD", @@ -35,7 +35,7 @@ "multisend": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", } ), - ChainType.OPTIMISM: ContractAddresses( + Chain.OPTIMISTIC: ContractAddresses( { "service_manager": "0xFbBEc0C8b13B38a9aC0499694A69a10204c5E2aB", "service_registry": "0x3d77596beb0f130a4415df3D2D8232B3d3D31e44", @@ -45,7 +45,7 @@ "multisend": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", } ), - ChainType.ETHEREUM: ContractAddresses( + Chain.ETHEREUM: ContractAddresses( { "service_manager": "0x2EA682121f815FBcF86EA3F3CaFdd5d67F2dB143", "service_registry": "0x48b6af7B12C71f09e2fC8aF4855De4Ff54e775cA", @@ -55,7 +55,7 @@ "multisend": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", } ), - ChainType.BASE: ContractAddresses( + Chain.BASE: ContractAddresses( { "service_manager": "0x63e66d7ad413C01A7b49C7FF4e3Bb765C4E4bd1b", "service_registry": "0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE", @@ -65,7 +65,7 @@ "multisend": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D", } ), - ChainType.MODE: ContractAddresses( + Chain.MODE: ContractAddresses( { "service_manager": "0x63e66d7ad413C01A7b49C7FF4e3Bb765C4E4bd1b", "service_registry": "0x3C1fF68f5aa342D296d4DEe4Bb1cACCA912D95fE", @@ -77,8 +77,8 @@ ), } -STAKING: t.Dict[ChainType, t.Dict[str, str]] = { - ChainType.GNOSIS: { +STAKING: t.Dict[Chain, t.Dict[str, str]] = { + Chain.GNOSIS: { "pearl_alpha": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A", "pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d", "pearl_beta_2": "0x1c2F82413666d2a3fD8bC337b0268e62dDF67434", @@ -87,20 +87,20 @@ "pearl_beta_5": "0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4", "pearl_beta_mech_marketplace": "0xDaF34eC46298b53a3d24CBCb431E84eBd23927dA", }, - ChainType.OPTIMISM: { + Chain.OPTIMISTIC: { "optimus_alpha": "0x88996bbdE7f982D93214881756840cE2c77C4992", }, - ChainType.ETHEREUM: {}, - ChainType.BASE: {}, - ChainType.MODE: { + Chain.ETHEREUM: {}, + Chain.BASE: {}, + Chain.MODE: { "optimus_alpha": "0x5fc25f50E96857373C64dC0eDb1AbCBEd4587e91", }, } -OLAS: t.Dict[ChainType, str] = { - ChainType.GNOSIS: "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", - ChainType.OPTIMISM: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527", - ChainType.BASE: "0x54330d28ca3357F294334BDC454a032e7f353416", - ChainType.ETHEREUM: "0x0001A500A6B18995B03f44bb040A5fFc28E45CB0", - ChainType.MODE: "0xcfD1D50ce23C46D3Cf6407487B2F8934e96DC8f9", +OLAS: t.Dict[Chain, str] = { + Chain.GNOSIS: "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", + Chain.OPTIMISTIC: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527", + Chain.BASE: "0x54330d28ca3357F294334BDC454a032e7f353416", + Chain.ETHEREUM: "0x0001A500A6B18995B03f44bb040A5fFc28E45CB0", + Chain.MODE: "0xcfD1D50ce23C46D3Cf6407487B2F8934e96DC8f9", } diff --git a/operate/operate_types.py b/operate/operate_types.py index 36482a0e7..a7194806d 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -20,9 +20,13 @@ """Types module.""" import enum +import os +from types import MethodType import typing as t from dataclasses import dataclass +from autonomy.chain.config import ChainType +from autonomy.chain.constants import CHAIN_NAME_TO_CHAIN_ID from typing_extensions import TypedDict from operate.resource import LocalResource @@ -35,45 +39,20 @@ "stop": 3, } - -_CHAIN_NAME_TO_ENUM = { - "ethereum": 0, - "goerli": 1, - "gnosis": 2, - "solana": 3, - "optimism": 4, - "base": 5, - "mode": 6, -} +CHAIN_NAME_TO_CHAIN_ID["mode"] = 34443 # TODO: update open-autonomy and remove this +CHAIN_NAME_TO_CHAIN_ID["solana"] = 900 _CHAIN_ID_TO_CHAIN_NAME = { - 1: "ethereum", - 5: "goerli", - 100: "gnosis", - 1399811149: "solana", - 10: "optimism", - 8453: "base", - 34443: "mode", -} - -_CHAIN_NAME_TO_ID = {val: key for key, val in _CHAIN_ID_TO_CHAIN_NAME.items()} - -_LEDGER_TYPE_TO_ENUM = { - "ethereum": 0, - "solana": 1, + chain_id: chain_name + for chain_name, chain_id in CHAIN_NAME_TO_CHAIN_ID.items() } -class LedgerType(enum.IntEnum): +class LedgerType(str, enum.Enum): """Ledger type enum.""" - ETHEREUM = 0 - SOLANA = 1 - - @classmethod - def from_string(cls, chain: str) -> "LedgerType": - """Load from string.""" - return cls(_LEDGER_TYPE_TO_ENUM[chain.lower()]) + ETHEREUM = "ethereum" + SOLANA = "solana" @property def config_file(self) -> str: @@ -85,32 +64,61 @@ def key_file(self) -> str: """Key filename.""" return f"{self.name.lower()}.txt" + @classmethod + def from_id(cls, chain_id: int) -> "LedgerType": + """Load from chain ID.""" + return Chain(_CHAIN_ID_TO_CHAIN_NAME[chain_id]).ledger_type + + +# Dynamically create the Chain enum from the ChainType +Chain = enum.Enum('Chain', [(member.name, member.value) for member in ChainType] + [ + ('MODE', 'mode'), # TODO: update open-autonomy version and remove this + ('SOLANA', 'solana'), +]) -class ChainType(enum.IntEnum): - """Chain type enum.""" - ETHEREUM = 0 - GOERLI = 1 - GNOSIS = 2 - SOLANA = 3 - OPTIMISM = 4 - BASE = 5 - MODE = 6 +class ChainMixin: + """Mixin for some new functions in the ChainType class.""" @property - def id(self) -> int: - """Returns chain id.""" - return _CHAIN_NAME_TO_ID[self.name.lower()] + def id(self) -> t.Optional[int]: + """Chain ID""" + if self == Chain.CUSTOM: + chain_id = os.environ.get("CUSTOM_CHAIN_ID") + if chain_id is None: + return None + return int(chain_id) + return CHAIN_NAME_TO_CHAIN_ID[self.value] + + @property + def ledger_type(self) -> LedgerType: + """Ledger type.""" + if self in ( + Chain.ETHEREUM, + Chain.GOERLI, + Chain.GNOSIS, + Chain.BASE, + Chain.OPTIMISTIC, + Chain.MODE, + ): + return LedgerType.ETHEREUM + return LedgerType.SOLANA @classmethod - def from_string(cls, chain: str) -> "ChainType": + def from_string(cls, chain: str) -> "Chain": """Load from string.""" - return cls(_CHAIN_NAME_TO_ENUM[chain.lower()]) + return Chain(chain.lower()) @classmethod - def from_id(cls, cid: int) -> "ChainType": + def from_id(cls, chain_id: int) -> "Chain": """Load from chain ID.""" - return cls(_CHAIN_NAME_TO_ENUM[_CHAIN_ID_TO_CHAIN_NAME[cid]]) + return Chain(_CHAIN_ID_TO_CHAIN_NAME[chain_id]) + + +# Add the ChainMixin methods to the Chain enum +for name in dir(ChainMixin): + if not name.startswith('__'): + setattr(Chain, name, getattr(ChainMixin, name)) class Action(enum.IntEnum): @@ -169,7 +177,7 @@ class LedgerConfig(LocalResource): rpc: str type: LedgerType - chain: ChainType + chain: Chain LedgerConfigs = t.Dict[str, LedgerConfig] @@ -232,7 +240,7 @@ class ServiceTemplate(TypedDict): image: str description: str service_version: str - home_chain_id: str + home_chain: str configurations: ConfigurationTemplates env_variables: EnvVariables diff --git a/operate/resource.py b/operate/resource.py index a82db9ad5..b0ddc6909 100644 --- a/operate/resource.py +++ b/operate/resource.py @@ -32,11 +32,11 @@ def serialize(obj: t.Any) -> t.Any: """Serialize object.""" if is_dataclass(obj): - return asdict(obj) + return serialize(asdict(obj)) if isinstance(obj, Path): return str(obj) if isinstance(obj, dict): - return {key: serialize(obj=value) for key, value in obj.items()} + return {serialize(key): serialize(obj=value) for key, value in obj.items()} if isinstance(obj, list): return [serialize(obj=value) for value in obj] if isinstance(obj, enum.Enum): diff --git a/operate/services/manage.py b/operate/services/manage.py index a20ff505d..1a498e113 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -38,7 +38,7 @@ from operate.keys import Key, KeysManager from operate.ledger import PUBLIC_RPCS from operate.ledger.profiles import CONTRACTS, OLAS, STAKING -from operate.operate_types import ChainType, LedgerConfig, ServiceTemplate +from operate.operate_types import Chain, LedgerConfig, ServiceTemplate from operate.services.protocol import EthSafeTxBuilder, OnChainManager, StakingState from operate.services.service import ( ChainConfig, @@ -109,8 +109,8 @@ def _get_all_services(self) -> t.List[Service]: except ValueError as e: raise e except Exception as e: # pylint: disable=broad-except - self.logger.warning( - f"Failed to load service: {path.name}. Exception: {e}" + self.logger.error( + f"Failed to load service: {path.name}. Exception: {traceback.format_exc()}" ) # rename the invalid path timestamp = int(time.time()) @@ -232,8 +232,8 @@ def create( return service - def _get_on_chain_state(self, service: Service, chain_id: str) -> OnChainState: - chain_config = service.chain_configs[chain_id] + def _get_on_chain_state(self, service: Service, chain: str) -> OnChainState: + chain_config = service.chain_configs[chain] chain_data = chain_config.chain_data ledger_config = chain_config.ledger_config if chain_data.token == NON_EXISTENT_TOKEN: @@ -273,23 +273,23 @@ def deploy_service_onchain( # pylint: disable=too-many-statements,too-many-loca # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. service = self.load(service_config_id=service_config_id) - for chain_id in service.chain_configs.keys(): + for chain in service.chain_configs.keys(): self._deploy_service_onchain( service_config_id=service_config_id, - chain_id=chain_id, + chain=chain, ) def _deploy_service_onchain( # pylint: disable=too-many-statements,too-many-locals self, service_config_id: str, - chain_id: str, + chain: str, ) -> None: """Deploy as service on-chain""" # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. - self.logger.info(f"_deploy_service_onchain_from_safe {chain_id=}") + self.logger.info(f"_deploy_service_onchain_from_safe {chain=}") service = self.load(service_config_id=service_config_id) - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data user_params = chain_config.chain_data.user_params @@ -367,7 +367,7 @@ def _deploy_service_onchain( # pylint: disable=too-many-statements,too-many-loc "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) + self._get_on_chain_state(service=service, chain=chain) == OnChainState.NON_EXISTENT ) is_update = ( @@ -474,22 +474,22 @@ def deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too """Deploy as service on-chain""" service = self.load(service_config_id=service_config_id) - for chain_id in service.chain_configs.keys(): + for chain in service.chain_configs.keys(): self._deploy_service_onchain_from_safe( service_config_id=service_config_id, - chain_id=chain_id, + chain=chain, ) def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals self, service_config_id: str, - chain_id: str, + chain: str, ) -> None: """Deploy service on-chain""" - self.logger.info(f"_deploy_service_onchain_from_safe {chain_id=}") + self.logger.info(f"_deploy_service_onchain_from_safe {chain=}") service = self.load(service_config_id=service_config_id) - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data user_params = chain_config.chain_data.user_params @@ -497,8 +497,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to instances = [key.address for key in keys] wallet = self.wallet_manager.load(ledger_config.type) sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) - chain_type = ChainType.from_id(int(chain_id)) - safe = wallet.safes[chain_type] # type: ignore + safe = wallet.safes[Chain(chain)] # TODO fix this os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc @@ -533,10 +532,10 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to # TODO A customized, arbitrary computation mechanism should be devised. env_var_to_value = { - "ETHEREUM_LEDGER_RPC": PUBLIC_RPCS[ChainType.ETHEREUM], - "GNOSIS_LEDGER_RPC": PUBLIC_RPCS[ChainType.GNOSIS], - "BASE_LEDGER_RPC": PUBLIC_RPCS[ChainType.BASE], - "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[ChainType.OPTIMISM], + "ETHEREUM_LEDGER_RPC": PUBLIC_RPCS[Chain.ETHEREUM], + "GNOSIS_LEDGER_RPC": PUBLIC_RPCS[Chain.GNOSIS], + "BASE_LEDGER_RPC": PUBLIC_RPCS[Chain.BASE], + "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[Chain.OPTIMISTIC], "STAKING_CONTRACT_ADDRESS": staking_params.get("staking_contract"), "MECH_ACTIVITY_CHECKER_CONTRACT": staking_params.get("activity_checker"), "MECH_CONTRACT_ADDRESS": staking_params.get("agent_mech"), @@ -544,7 +543,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to "USE_MECH_MARKETPLACE": str( "mech_marketplace" in service.chain_configs[ - service.home_chain_id + service.home_chain ].chain_data.user_params.staking_program_id ), "REQUESTER_STAKING_INSTANCE_ADDRESS": staking_params.get( @@ -602,7 +601,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to ) is_first_mint = ( - self._get_on_chain_state(service=service, chain_id=chain_id) + self._get_on_chain_state(service=service, chain=chain) == OnChainState.NON_EXISTENT ) is_update = ( @@ -635,11 +634,11 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to if is_update: self._terminate_service_on_chain_from_safe( - service_config_id=service_config_id, chain_id=chain_id + service_config_id=service_config_id, chain=chain ) # Update service if ( - self._get_on_chain_state(service=service, chain_id=chain_id) + self._get_on_chain_state(service=service, chain=chain) == OnChainState.PRE_REGISTRATION ): self.logger.info("Updating service") @@ -681,7 +680,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to # Mint service if ( - self._get_on_chain_state(service=service, chain_id=chain_id) + self._get_on_chain_state(service=service, chain=chain) == OnChainState.NON_EXISTENT ): if user_params.use_staking and not sftxb.staking_slots_available( @@ -730,7 +729,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() if ( - self._get_on_chain_state(service=service, chain_id=chain_id) + self._get_on_chain_state(service=service, chain=chain) == OnChainState.PRE_REGISTRATION ): # TODO Verify that this is incorrect: cost_of_bond = staking_params["min_staking_deposit"] @@ -783,7 +782,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() if ( - self._get_on_chain_state(service=service, chain_id=chain_id) + self._get_on_chain_state(service=service, chain=chain) == OnChainState.ACTIVE_REGISTRATION ): cost_of_bond = user_params.cost_of_bond @@ -839,7 +838,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() if ( - self._get_on_chain_state(service=service, chain_id=chain_id) + self._get_on_chain_state(service=service, chain=chain) == OnChainState.FINISHED_REGISTRATION ): self.logger.info("Deploying service") @@ -872,11 +871,11 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to service.store() if user_params.use_staking: self.stake_service_on_chain_from_safe( - service_config_id=service_config_id, chain_id=chain_id + service_config_id=service_config_id, chain=chain ) def terminate_service_on_chain( - self, service_config_id: str, chain_id: t.Optional[str] = None + self, service_config_id: str, chain: t.Optional[str] = None ) -> None: """Terminate service on-chain""" # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. @@ -884,10 +883,7 @@ def terminate_service_on_chain( self.logger.info("terminate_service_on_chain") service = self.load(service_config_id=service_config_id) - if chain_id is None: - chain_id = service.home_chain_id - - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain or service.home_chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data ocm = self.get_on_chain_manager(ledger_config=ledger_config) @@ -911,20 +907,19 @@ def terminate_service_on_chain( service.store() def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals - self, service_config_id: str, chain_id: str + self, service_config_id: str, chain: str ) -> None: """Terminate service on-chain""" self.logger.info("terminate_service_on_chain_from_safe") service = self.load(service_config_id=service_config_id) - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data keys = service.keys instances = [key.address for key in keys] wallet = self.wallet_manager.load(ledger_config.type) - chain_type = ChainType.from_id(int(chain_id)) - safe = wallet.safes[chain_type] # type: ignore + safe = wallet.safes[Chain(chain)] # type: ignore # TODO fixme os.environ["CUSTOM_CHAIN_RPC"] = ledger_config.rpc @@ -955,11 +950,11 @@ def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals if is_staked and can_unstake: self.unstake_service_on_chain_from_safe( service_config_id=service_config_id, - chain_id=chain_id, + chain=chain, staking_program_id=current_staking_program, ) - if self._get_on_chain_state(service=service, chain_id=chain_id) in ( + if self._get_on_chain_state(service=service, chain=chain) in ( OnChainState.ACTIVE_REGISTRATION, OnChainState.FINISHED_REGISTRATION, OnChainState.DEPLOYED, @@ -972,7 +967,7 @@ def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals ).settle() if ( - self._get_on_chain_state(service=service, chain_id=chain_id) + self._get_on_chain_state(service=service, chain=chain) == OnChainState.TERMINATED_BONDED ): self.logger.info("Unbonding service") @@ -1030,17 +1025,14 @@ def _get_current_staking_program( return current_staking_program def unbond_service_on_chain( - self, service_config_id: str, chain_id: t.Optional[str] = None + self, service_config_id: str, chain: t.Optional[str] = None ) -> None: """Unbond service on-chain""" # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. service = self.load(service_config_id=service_config_id) - if chain_id is None: - chain_id = service.home_chain_id - - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain or service.home_chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data ocm = self.get_on_chain_manager(ledger_config=ledger_config) @@ -1072,12 +1064,12 @@ def stake_service_on_chain(self, hash: str) -> None: raise NotImplementedError def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too-many-locals - self, service_config_id: str, chain_id: str + self, service_config_id: str, chain: str ) -> None: """Stake service on-chain""" service = self.load(service_config_id=service_config_id) - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data user_params = chain_data.user_params @@ -1110,7 +1102,7 @@ def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too ) self.unstake_service_on_chain_from_safe( service_config_id=service_config_id, - chain_id=chain_id, + chain=chain, staking_program_id=current_staking_program, ) @@ -1127,7 +1119,7 @@ def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too ) self.unstake_service_on_chain_from_safe( service_config_id=service_config_id, - chain_id=chain_id, + chain=chain, staking_program_id=current_staking_program, ) @@ -1142,7 +1134,7 @@ def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too ) self.unstake_service_on_chain_from_safe( service_config_id=service_config_id, - chain_id=chain_id, + chain=chain, staking_program_id=current_staking_program, ) @@ -1156,7 +1148,7 @@ def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too ) self.unstake_service_on_chain_from_safe( service_config_id=service_config_id, - chain_id=chain_id, + chain=chain, staking_program_id=current_staking_program, ) @@ -1170,7 +1162,7 @@ def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too target_staking_contract ) staking_slots_available = sftxb.staking_slots_available(target_staking_contract) - on_chain_state = self._get_on_chain_state(service=service, chain_id=chain_id) + on_chain_state = self._get_on_chain_state(service=service, chain=chain) current_staking_program = self._get_current_staking_program( chain_data, ledger_config, sftxb ) @@ -1218,17 +1210,13 @@ def stake_service_on_chain_from_safe( # pylint: disable=too-many-statements,too self.logger.info(f"{current_staking_program=}") def unstake_service_on_chain( - self, service_config_id: str, chain_id: t.Optional[str] = None + self, service_config_id: str, chain: t.Optional[str] = None ) -> None: """Unbond service on-chain""" # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. service = self.load(service_config_id=service_config_id) - - if chain_id is None: - chain_id = service.home_chain_id - - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain or service.home_chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data ocm = self.get_on_chain_manager(ledger_config=ledger_config) @@ -1258,14 +1246,14 @@ def unstake_service_on_chain( def unstake_service_on_chain_from_safe( self, service_config_id: str, - chain_id: str, + chain: str, staking_program_id: t.Optional[str] = None, ) -> None: """Unbond service on-chain""" self.logger.info("unstake_service_on_chain_from_safe") service = self.load(service_config_id=service_config_id) - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data @@ -1314,8 +1302,8 @@ def fund_service( # pylint: disable=too-many-arguments,too-many-locals """Fund service if required.""" service = self.load(service_config_id=service_config_id) - for chain_id in service.chain_configs.keys(): - self.logger.info(f"Funding chain_id {chain_id}") + for chain in service.chain_configs.keys(): + self.logger.info(f"Funding {chain=}") self.fund_service_single_chain( service_config_id=service_config_id, rpc=rpc, @@ -1324,7 +1312,7 @@ def fund_service( # pylint: disable=too-many-arguments,too-many-locals agent_fund_threshold=agent_fund_threshold, safe_fund_treshold=safe_fund_treshold, from_safe=from_safe, - chain_id=chain_id, + chain=chain, ) def fund_service_single_chain( # pylint: disable=too-many-arguments,too-many-locals @@ -1336,17 +1324,17 @@ def fund_service_single_chain( # pylint: disable=too-many-arguments,too-many-lo agent_fund_threshold: t.Optional[float] = None, safe_fund_treshold: t.Optional[float] = None, from_safe: bool = True, - chain_id: str = "100", + chain: str = "gnosis", ) -> None: """Fund service if required.""" service = self.load(service_config_id=service_config_id) - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] 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 or ledger_config.rpc + chain=ledger_config.chain, rpc=rpc or ledger_config.rpc ) agent_fund_threshold = ( agent_fund_threshold @@ -1404,16 +1392,16 @@ def fund_service_erc20( # pylint: disable=too-many-arguments,too-many-locals agent_fund_threshold: t.Optional[float] = None, safe_fund_treshold: t.Optional[float] = None, from_safe: bool = True, - chain_id: str = "100", + chain: str = "gnosis", ) -> None: """Fund service if required.""" service = self.load(service_config_id=service_config_id) - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] 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 or ledger_config.rpc + chain=ledger_config.chain, rpc=rpc or ledger_config.rpc ) agent_fund_threshold = ( agent_fund_threshold or chain_data.user_params.fund_requirements.agent @@ -1471,8 +1459,7 @@ async def funding_job( """Start a background funding job.""" loop = loop or asyncio.get_event_loop() service = self.load(service_config_id=service_config_id) - chain_id = service.home_chain_id - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[service.home_chain] ledger_config = chain_config.ledger_config with ThreadPoolExecutor() as executor: while True: @@ -1501,7 +1488,7 @@ def deploy_service_locally( self, service_config_id: str, force: bool = True, - chain_id: t.Optional[str] = None, + chain: t.Optional[str] = None, use_docker: bool = False, ) -> Deployment: """ @@ -1509,7 +1496,7 @@ def deploy_service_locally( :param hash: Service hash :param force: Remove previous deployment and start a new one. - :param chain_id: Chain ID to set runtime parameters on the deployment (home_chain_id if not provided). + :param chain: Chain to set runtime parameters on the deployment (home_chain if not provided). :param use_docker: Use a Docker Compose deployment (True) or Host deployment (False). :return: Deployment instance """ @@ -1517,7 +1504,7 @@ def deploy_service_locally( service = self.load(service_config_id=service_config_id) deployment = service.deployment - deployment.build(use_docker=use_docker, force=force, chain_id=chain_id) + deployment.build(use_docker=use_docker, force=force, chain=chain or service.home_chain) deployment.start(use_docker=use_docker) return deployment diff --git a/operate/services/protocol.py b/operate/services/protocol.py index a2d79350f..5444d4bae 100644 --- a/operate/services/protocol.py +++ b/operate/services/protocol.py @@ -67,7 +67,7 @@ from operate.data import DATA_DIR from operate.data.contracts.staking_token.contract import StakingTokenContract from operate.ledger.profiles import STAKING -from operate.operate_types import ChainType as OperateChainType +from operate.operate_types import Chain as OperateChain from operate.operate_types import ContractAddresses from operate.utils.gnosis import ( MultiSendOperation, @@ -520,12 +520,12 @@ def _patch(self) -> None: def safe(self) -> str: """Get safe address.""" chain_id = self.ledger_api.api.eth.chain_id - chain_type = OperateChainType.from_id(chain_id) + chain = OperateChain.from_id(chain_id) if self.wallet.safes is None: raise ValueError("Safes not initialized") - if chain_type not in self.wallet.safes: - raise ValueError(f"Safe for chain type {chain_type} not found") - return self.wallet.safes[chain_type] + if chain not in self.wallet.safes: + raise ValueError(f"Safe for chain type {chain} not found") + return self.wallet.safes[chain] @property def crypto(self) -> Crypto: @@ -807,7 +807,7 @@ def get_staking_params(self, staking_contract: str) -> t.Dict: # TODO Read from activity checker contract. Read remaining variables for marketplace. if ( staking_contract - == STAKING[operate.operate_types.ChainType.GNOSIS][ + == STAKING[operate.operate_types.Chain.GNOSIS][ "pearl_beta_mech_marketplace" ] ): diff --git a/operate/services/service.py b/operate/services/service.py index 9685cc499..8baa0e3ba 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -72,7 +72,7 @@ from operate.operate_types import ( ChainConfig, ChainConfigs, - ChainType, + Chain, DeployedNodes, DeploymentConfig, DeploymentStatus, @@ -97,7 +97,7 @@ ALL_PARTICIPANTS = "all_participants" CONSENSUS_THRESHOLD = "consensus_threshold" DELETE_PREFIX = "delete_" -SERVICE_CONFIG_VERSION = 4 +SERVICE_CONFIG_VERSION = 5 SERVICE_CONFIG_PREFIX = "sc-" DUMMY_MULTISIG = "0xm" @@ -262,7 +262,7 @@ def ledger_configs(self) -> LedgerConfigs: ): for _, config in override["config"]["ledger_apis"].items(): # TODO chain name is inferred from the chain_id. The actual id provided on service.yaml is ignored. - chain = ChainType.from_id(cid=config["chain_id"]) + chain = Chain.from_id(chain_id=config["chain_id"]) ledger_configs[str(config["chain_id"])] = LedgerConfig( rpc=config["address"], chain=chain, @@ -395,7 +395,7 @@ def load(cls, path: Path) -> "Deployment": def _build_docker( self, force: bool = True, - chain_id: t.Optional[str] = None, + chain: t.Optional[str] = None, ) -> None: """Build docker deployment.""" service = Service.load(path=self.path) @@ -438,10 +438,10 @@ def _build_docker( builder.deplopyment_type = DockerComposeGenerator.deployment_type builder.try_update_abci_connection_params() - if not chain_id: - chain_id = service.home_chain_id + if not chain: + chain = service.home_chain - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data @@ -453,7 +453,7 @@ def _build_docker( ) # TODO: Support for multiledger builder.try_update_ledger_params( - chain=LedgerType(ledger_config.type).name.lower(), + chain=chain, address=ledger_config.rpc, ) @@ -502,7 +502,7 @@ def _build_docker( self.status = DeploymentStatus.BUILT self.store() - def _build_host(self, force: bool = True, chain_id: t.Optional[str] = None) -> None: + def _build_host(self, force: bool = True, chain: t.Optional[str] = None) -> None: """Build host depployment.""" build = self.path / DEPLOYMENT if build.exists() and not force: @@ -526,10 +526,10 @@ def _build_host(self, force: bool = True, chain_id: t.Optional[str] = None) -> N "Host deployment currently only supports single agent deployments" ) - if not chain_id: - chain_id = service.home_chain_id + if not chain: + chain = service.home_chain - chain_config = service.chain_configs[chain_id] + chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data @@ -592,20 +592,20 @@ def build( self, use_docker: bool = False, force: bool = True, - chain_id: t.Optional[str] = None, + chain: t.Optional[str] = None, ) -> None: """ Build a deployment :param use_docker: Use a Docker Compose deployment (True) or Host deployment (False). :param force: Remove existing deployment and build a new one - :param chain_id: Chain ID to set runtime parameters on the deployment (home_chain_id if not provided). + :param chain: Chain to set runtime parameters on the deployment (home_chain if not provided). :return: Deployment object """ - # TODO: Maybe remove usage of chain_id and use home_chain_id always? + # TODO: Maybe remove usage of chain and use home_chain always? if use_docker: - return self._build_docker(force=force, chain_id=chain_id) - return self._build_host(force=force, chain_id=chain_id) + return self._build_docker(force=force, chain=chain) + return self._build_host(force=force, chain=chain) def start(self, use_docker: bool = False) -> None: """Start the service""" @@ -662,7 +662,7 @@ class Service(LocalResource): hash: str hash_history: t.Dict[int, str] keys: Keys - home_chain_id: str + home_chain: str chain_configs: ChainConfigs description: str env_variables: EnvVariables @@ -707,9 +707,9 @@ def migrate_format(cls, path: Path) -> bool: "version": 2, "hash": data.get("hash"), "keys": data.get("keys"), - "home_chain_id": "100", # Assuming a default value for home_chain_id + "home_chain": "gnosis", # Assuming a default value for home_chain "chain_configs": { - "100": { + "gnosis": { "ledger_config": { "rpc": data.get("ledger_config", {}).get("rpc"), "type": data.get("ledger_config", {}).get("type"), @@ -780,7 +780,25 @@ def migrate_format(cls, path: Path) -> bool: ) data["service_path"] = str(service_path) - data["version"] = 4 + old_to_new_ledgers = ["ethereum", "solana"] + for key_data in data["keys"]: + key_data["ledger"] = old_to_new_ledgers[key_data["ledger"]] + + old_to_new_chains = ["ethereum", "goerli", "gnosis", "solana", "optimistic", "base", "mode"] + new_chain_configs = {} + for chain_id, chain_data in data["chain_configs"].items(): + chain_data["ledger_config"]["chain"] = old_to_new_chains[chain_data["ledger_config"]["chain"]] + chain_data["ledger_config"]["type"] = old_to_new_ledgers[chain_data["ledger_config"]["type"]] + new_chain_configs[Chain.from_id(int(chain_id)).value] = chain_data + + data["chain_configs"] = new_chain_configs + data["home_chain"] = Chain.from_id(int(data["home_chain"])).value + del data["home_chain"] + + if "env_variables" not in data: + data["env_variables"] = {} + + data["version"] = 5 with open(path / Service._file, "w", encoding="utf-8") as file: json.dump(data, file, indent=2) @@ -857,7 +875,7 @@ def new( # pylint: disable=too-many-locals description=service_template["description"], hash=service_template["hash"], keys=keys, - home_chain_id=service_template["home_chain_id"], + home_chain=service_template["home_chain"], hash_history={current_timestamp: service_template["hash"]}, chain_configs=chain_configs, path=service_path.parent, @@ -953,7 +971,7 @@ def update( self.hash_history[current_timestamp] = service_template["hash"] self.description = service_template["description"] - self.home_chain_id = service_template["home_chain_id"] + self.home_chain = service_template["home_chain"] ledger_configs = ServiceHelper(path=self.service_path).ledger_configs() for chain, config in service_template["configurations"].items(): diff --git a/operate/wallet/master.py b/operate/wallet/master.py index e3ec758ef..fa0a1cf1f 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -40,7 +40,7 @@ ON_CHAIN_INTERACT_TIMEOUT, ) from operate.ledger import get_default_rpc -from operate.operate_types import ChainType, LedgerType +from operate.operate_types import Chain, LedgerType from operate.resource import LocalResource from operate.utils.gnosis import add_owner from operate.utils.gnosis import create_safe as create_gnosis_safe @@ -53,8 +53,8 @@ class MasterWallet(LocalResource): """Master wallet.""" path: Path - safes: t.Optional[t.Dict[ChainType, str]] = {} - safe_chains: t.List[ChainType] = [] + safes: t.Optional[t.Dict[Chain, str]] = {} + safe_chains: t.List[Chain] = [] ledger_type: LedgerType _key: str @@ -88,21 +88,21 @@ def key_path(self) -> Path: def ledger_api( self, - chain_type: ChainType, + chain: Chain, rpc: t.Optional[str] = None, ) -> LedgerApi: """Get ledger api object.""" return make_ledger_api( self.ledger_type.name.lower(), - address=(rpc or get_default_rpc(chain=chain_type)), - chain_id=chain_type.id, + address=(rpc or get_default_rpc(chain=chain)), + chain_id=chain.id, ) def transfer( self, to: str, amount: int, - chain_type: ChainType, + chain_type: Chain, from_safe: bool = True, rpc: t.Optional[str] = None, ) -> None: @@ -115,7 +115,7 @@ def transfer_erc20( token: str, to: str, amount: int, - chain_type: ChainType, + chain_type: Chain, from_safe: bool = True, rpc: t.Optional[str] = None, ) -> None: @@ -129,7 +129,7 @@ def new(password: str, path: Path) -> t.Tuple["MasterWallet", t.List[str]]: def create_safe( self, - chain_type: ChainType, + chain_type: Chain, owner: t.Optional[str] = None, rpc: t.Optional[str] = None, ) -> None: @@ -138,7 +138,7 @@ def create_safe( def add_backup_owner( self, - chain_type: ChainType, + chain_type: Chain, owner: str, rpc: t.Optional[str] = None, ) -> None: @@ -147,7 +147,7 @@ def add_backup_owner( def swap_backup_owner( self, - chain_type: ChainType, + chain_type: Chain, old_owner: str, new_owner: str, rpc: t.Optional[str] = None, @@ -157,7 +157,7 @@ def swap_backup_owner( def add_or_swap_owner( self, - chain_type: ChainType, + chain_type: Chain, owner: str, rpc: t.Optional[str] = None, ) -> None: @@ -177,8 +177,8 @@ class EthereumMasterWallet(MasterWallet): path: Path address: str - safes: t.Optional[t.Dict[ChainType, str]] = field(default_factory=dict) # type: ignore - safe_chains: t.List[ChainType] = field(default_factory=list) # type: ignore + safes: t.Optional[t.Dict[Chain, str]] = field(default_factory=dict) # type: ignore + safe_chains: t.List[Chain] = field(default_factory=list) # type: ignore ledger_type: LedgerType = LedgerType.ETHEREUM safe_nonce: t.Optional[int] = None # For cross-chain reusability @@ -187,11 +187,11 @@ class EthereumMasterWallet(MasterWallet): _crypto_cls = EthereumCrypto def _transfer_from_eoa( - self, to: str, amount: int, chain_type: ChainType, rpc: t.Optional[str] = None + self, to: str, amount: int, chain_type: Chain, rpc: t.Optional[str] = None ) -> None: """Transfer funds from EOA wallet.""" ledger_api = t.cast( - EthereumApi, self.ledger_api(chain_type=chain_type, rpc=rpc) + EthereumApi, self.ledger_api(chain=chain_type, rpc=rpc) ) tx_helper = TxSettler( ledger_api=ledger_api, @@ -230,12 +230,12 @@ def _build_tx( # pylint: disable=unused-argument tx_helper.transact(lambda x: x, "", kwargs={}) def _transfer_from_safe( - self, to: str, amount: int, chain_type: ChainType, rpc: t.Optional[str] = None + self, to: str, amount: int, chain_type: Chain, rpc: t.Optional[str] = None ) -> None: """Transfer funds from safe wallet.""" if self.safes is not None: transfer_from_safe( - ledger_api=self.ledger_api(chain_type=chain_type, rpc=rpc), + ledger_api=self.ledger_api(chain=chain_type, rpc=rpc), crypto=self.crypto, safe=t.cast(str, self.safes[chain_type]), to=to, @@ -249,12 +249,12 @@ def _transfer_erc20_from_safe( token: str, to: str, amount: int, - chain_type: ChainType, + chain_type: Chain, rpc: t.Optional[str] = None, ) -> None: """Transfer funds from safe wallet.""" transfer_erc20_from_safe( - ledger_api=self.ledger_api(chain_type=chain_type, rpc=rpc), + ledger_api=self.ledger_api(chain=chain_type, rpc=rpc), crypto=self.crypto, token=token, safe=t.cast(str, self.safes[chain_type]), # type: ignore @@ -266,7 +266,7 @@ def transfer( self, to: str, amount: int, - chain_type: ChainType, + chain_type: Chain, from_safe: bool = True, rpc: t.Optional[str] = None, ) -> None: @@ -291,7 +291,7 @@ def transfer_erc20( token: str, to: str, amount: int, - chain_type: ChainType, + chain_type: Chain, from_safe: bool = True, rpc: t.Optional[str] = None, ) -> None: @@ -334,7 +334,7 @@ def new( def create_safe( self, - chain_type: ChainType, + chain_type: Chain, owner: t.Optional[str] = None, rpc: t.Optional[str] = None, ) -> None: @@ -342,7 +342,7 @@ def create_safe( if chain_type in self.safe_chains: return safe, self.safe_nonce = create_gnosis_safe( - ledger_api=self.ledger_api(chain_type=chain_type, rpc=rpc), + ledger_api=self.ledger_api(chain=chain_type, rpc=rpc), crypto=self.crypto, owner=owner, salt_nonce=self.safe_nonce, @@ -355,12 +355,12 @@ def create_safe( def add_backup_owner( self, - chain_type: ChainType, + chain_type: Chain, owner: str, rpc: t.Optional[str] = None, ) -> None: """Add a backup owner.""" - ledger_api = self.ledger_api(chain_type=chain_type, rpc=rpc) + ledger_api = self.ledger_api(chain=chain_type, rpc=rpc) if chain_type not in self.safes: # type: ignore raise ValueError(f"Safes not created for chain_type {chain_type}!") safe = t.cast(str, self.safes[chain_type]) # type: ignore @@ -375,13 +375,13 @@ def add_backup_owner( def swap_backup_owner( self, - chain_type: ChainType, + chain_type: Chain, old_owner: str, new_owner: str, rpc: t.Optional[str] = None, ) -> None: """Swap backup owner.""" - ledger_api = self.ledger_api(chain_type=chain_type, rpc=rpc) + ledger_api = self.ledger_api(chain=chain_type, rpc=rpc) if chain_type not in self.safes: # type: ignore raise ValueError(f"Safes not created for chain_type {chain_type}!") safe = t.cast(str, self.safes[chain_type]) # type: ignore @@ -397,12 +397,12 @@ def swap_backup_owner( def add_or_swap_owner( self, - chain_type: ChainType, + chain_type: Chain, owner: str, rpc: t.Optional[str] = None, ) -> None: """Add or swap backup owner.""" - ledger_api = self.ledger_api(chain_type=chain_type, rpc=rpc) + ledger_api = self.ledger_api(chain=chain_type, rpc=rpc) if self.safes is None or chain_type not in self.safes: raise ValueError(f"Safes not created for chain_type {chain_type}!") safe = t.cast(str, self.safes[chain_type]) @@ -429,13 +429,13 @@ def load(cls, path: Path) -> "EthereumMasterWallet": # The reason for that is that wallet.safes[chain_type] would fail # (for example in service manager) when passed a ChainType key. - raw_ethereum_wallet = super().load(path) # type: ignore + raw_ethereum_wallet = t.cast(EthereumMasterWallet, super().load(path)) # type: ignore safes = {} - for id_, safe_address in raw_ethereum_wallet.safes.items(): # type: ignore - safes[ChainType(int(id_))] = safe_address + for chain, safe_address in raw_ethereum_wallet.safes.items(): + safes[Chain(chain)] = safe_address - raw_ethereum_wallet.safes = safes # type: ignore - return t.cast(EthereumMasterWallet, raw_ethereum_wallet) + raw_ethereum_wallet.safes = safes + return raw_ethereum_wallet @classmethod def migrate_format(cls, path: Path) -> bool: @@ -453,6 +453,30 @@ def migrate_format(cls, path: Path) -> bool: data["safes"] = safes migrated = True + old_to_new_chains = ["ethereum", "goerli", "gnosis", "solana", "optimistic", "base", "mode"] + safe_chains = [] + for chain in data["safe_chains"]: + if isinstance(chain, int): + safe_chains.append(old_to_new_chains[chain]) + migrated = True + else: + safe_chains.append(chain) + data["safe_chains"] = safe_chains + + if isinstance(data["ledger_type"], int): + old_to_new_ledgers = [ledger_type.value for ledger_type in LedgerType] + data["ledger_type"] = old_to_new_ledgers[data["ledger_type"]] + migrated = True + + safes = {} + for chain, address in data["safes"].items(): + if chain.isnumeric(): + safes[old_to_new_chains[int(chain)]] = address + migrated = True + else: + safes[chain] = address + data["safes"] = safes + with open(wallet_path, "w", encoding="utf-8") as file: json.dump(data, file, indent=2) @@ -549,9 +573,10 @@ def migrate_wallet_configs(self) -> None: print(self.path) for ledger_type in LedgerType: - if not self.exists(ledger_type=ledger_type): + wallet_class = LEDGER_TYPE_TO_WALLET_CLASS.get(ledger_type) + if wallet_class is None: continue - wallet_class = LEDGER_TYPE_TO_WALLET_CLASS[ledger_type] + migrated = wallet_class.migrate_format(path=self.path) if migrated: self.logger.info(f"Wallet {wallet_class} has been migrated.") diff --git a/scripts/setup_wallet.py b/scripts/setup_wallet.py index 5d5a47f70..78336f6df 100644 --- a/scripts/setup_wallet.py +++ b/scripts/setup_wallet.py @@ -21,7 +21,7 @@ import requests -from operate.operate_types import ChainType +from operate.operate_types import Chain from scripts.fund import fund @@ -48,7 +48,7 @@ wallet = requests.post( "http://localhost:8000/api/wallet", json={ - "chain_type": ChainType.GNOSIS, + "chain_type": Chain.GNOSIS, }, ).json() print("Setting up wallet") @@ -61,7 +61,7 @@ requests.post( "http://localhost:8000/api/wallet/safe", json={ - "chain_type": ChainType.GNOSIS, + "chain_type": Chain.GNOSIS, "owner": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", # Backup owner }, ).json() diff --git a/templates/optimus.yaml b/templates/optimus.yaml index 331c61eb3..4076c9bb5 100644 --- a/templates/optimus.yaml +++ b/templates/optimus.yaml @@ -3,9 +3,9 @@ hash: bafybeibiiuhqronhgkxjo7x5xve24lkbqom5rqcjxg7vrl6jwavfyypmhu description: Optimus image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 service_version: v0.2.9 -home_chain_id: 10 +home_chain: "optimistic" configurations: - 1: + ethereum: staking_program_id: optimus_alpha nft: bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq agent_id: 14 @@ -17,7 +17,7 @@ configurations: fund_requirements: agent: 1000 safe: 1000 - 10: + optimistic: staking_program_id: optimus_alpha nft: bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq agent_id: 14 @@ -29,7 +29,7 @@ configurations: fund_requirements: agent: 1000 safe: 1000 - 8453: + base: staking_program_id: optimus_alpha nft: bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq agent_id: 14 diff --git a/templates/trader.yaml b/templates/trader.yaml index 7c9e4b3bb..cf639bf46 100644 --- a/templates/trader.yaml +++ b/templates/trader.yaml @@ -3,9 +3,9 @@ description: "A single-agent service (sovereign agent) placing bets on Omen" hash: bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u image: https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75 service_version: v0.18.4 -home_chain_id: 100 +home_chain: "gnosis" configurations: - 100: + gnosis: staking_program_id: pearl_beta nft: bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq rpc: http://localhost:8545 # User provided From 6822d3cd3e094357e8a3a1996d353ac019dfce92 Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Thu, 14 Nov 2024 18:15:01 +0530 Subject: [PATCH 206/463] chore: update docs and a TODO Signed-off-by: OjusWiZard --- api.md | 18 +++++++++--------- operate/operate_types.py | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/api.md b/api.md index 60eac290d..650c1dfd4 100644 --- a/api.md +++ b/api.md @@ -295,7 +295,7 @@ Returns the list of existing service configurations. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, - "home_chain": "100", + "home_chain": "gnosis", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -324,7 +324,7 @@ Create a service configuration using a template. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", - "home_chain": "100", + "home_chain": "gnosis", "name": "valory/trader_omen_gnosis", "service_version": "v0.18.4" } @@ -342,7 +342,7 @@ Create a service configuration using a template. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, - "home_chain": "100", + "home_chain": "gnosis", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -369,7 +369,7 @@ Update all the service configurations whose Service Public ID match the Service "env_variables": {...}, "hash": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me", "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", - "home_chain": "100", + "home_chain": "gnosis", "name": "valory/trader_omen_gnosis", "service_version": "v0.19.0" } @@ -390,7 +390,7 @@ The response contains an array of the services which have been updated (an empty "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "1731490000": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me"}, - "home_chain": "100", + "home_chain": "gnosis", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -451,7 +451,7 @@ Returns the service configuration `service_config_id`. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, - "home_chain": "100", + "home_chain": "gnosis", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -498,7 +498,7 @@ The response contains the updated service configuration following the on-chain o "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u"}, - "home_chain": "100", + "home_chain": "gnosis", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", @@ -525,7 +525,7 @@ Update service configuration `service_config_id` with the provided template. "env_variables": {...}, "hash": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me", "image": "https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75", - "home_chain": "100", + "home_chain": "gnosis", "name": "valory/trader_omen_gnosis", "service_version": "v0.19.0" } @@ -545,7 +545,7 @@ Update service configuration `service_config_id` with the provided template. "env_variables": {...}, "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "hash_history": {"1731487112": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", "1731490000": "bafybeibpseosblmaw6sk6zsnic2kfxfsijrnfluuhkwboyqhx7ma7zw2me"}, - "home_chain": "100", + "home_chain": "gnosis", "keys": [...], "name": "valory/trader_omen_gnosis", "service_config_id": "sc-85a7a12a-8c6b-46b8-919a-b8a3b8e3ad39", diff --git a/operate/operate_types.py b/operate/operate_types.py index a7194806d..767e7729c 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -71,6 +71,9 @@ def from_id(cls, chain_id: int) -> "LedgerType": # Dynamically create the Chain enum from the ChainType +# TODO: Migrate this to open-autonomy and remove this modified version of Chain here and use the one from open-autonomy +# This version of open-autonomy must support the LedgerType to support SOLANA in the future +# If solana support is not fuly implemented, decide to keep this half-baked feature Chain = enum.Enum('Chain', [(member.name, member.value) for member in ChainType] + [ ('MODE', 'mode'), # TODO: update open-autonomy version and remove this ('SOLANA', 'solana'), From 55a64ec1464f216afa2364634c699e78de95c7f2 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:54:09 +0000 Subject: [PATCH 207/463] Update frontend/context/BalanceProvider.tsx Co-authored-by: Atatakai --- frontend/context/BalanceProvider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 746a42b81..7a985f8a5 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -51,7 +51,7 @@ export const BalanceContext = createContext<{ totalEthBalance?: number; totalOlasBalance?: number; isLowBalance: boolean; - wallets?: Wallets[]; + wallets?: Wallets; walletBalances: WalletAddressNumberRecord; agentSafeBalance?: ValueOf; agentEoaBalance?: ValueOf; From b8b67bf43e92eceedda42f764f30a8b7aab66631 Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Thu, 14 Nov 2024 19:32:03 +0530 Subject: [PATCH 208/463] refactor: ledger_config type and FE rebase Signed-off-by: OjusWiZard --- frontend/client/types.ts | 5 ++--- frontend/context/BalanceProvider.tsx | 16 ++++++++-------- frontend/context/StakingContractInfoProvider.tsx | 7 ++++--- frontend/context/StakingProgramProvider.tsx | 9 +++++---- frontend/hooks/useAddress.ts | 5 +++-- operate/operate_types.py | 1 - operate/services/manage.py | 12 ++++++------ operate/services/service.py | 9 ++++----- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 3533237c3..c9db25a6a 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -18,7 +18,6 @@ export type ServiceKeys = { export type LedgerConfig = { rpc: string; - type: MiddlewareLedger; chain: MiddlewareChain; }; @@ -50,12 +49,12 @@ export type MiddlewareServiceResponse = { hash_history: { [block: string]: string; }; - home_chain_id: number; + home_chain: MiddlewareChain; keys: ServiceKeys[]; service_path?: string; version: string; chain_configs: { - [chainId: number]: { + [chain in MiddlewareChain]: { ledger_config: LedgerConfig; chain_data: ChainData; }; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index c3fd0da45..2c573aada 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -63,7 +63,7 @@ export const BalanceContext = createContext<{ optimismBalance?: number; }>({ isLoaded: false, - setIsLoaded: () => {}, + setIsLoaded: () => { }, isBalanceLoaded: false, olasBondBalance: undefined, olasDepositBalance: undefined, @@ -76,8 +76,8 @@ export const BalanceContext = createContext<{ walletBalances: {}, agentSafeBalance: undefined, agentEoaBalance: undefined, - updateBalances: async () => {}, - setIsPaused: () => {}, + updateBalances: async () => { }, + setIsPaused: () => { }, totalOlasStakedBalance: undefined, baseBalance: undefined, ethereumBalance: undefined, @@ -171,7 +171,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { // TODO: refactor to use ChainId enum, service from useService(), const serviceId = - services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data + services?.[0]?.chain_configs[CHAIN_CONFIG[ChainId.Optimism].middlewareChain].chain_data .token; if (!isNumber(serviceId)) { @@ -232,7 +232,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { const agentEoaAddress = useMemo( () => - services?.[0]?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data + services?.[0]?.chain_configs?.[CHAIN_CONFIG[ChainId.Optimism].middlewareChain]?.chain_data ?.instances?.[0], [services], ); @@ -249,11 +249,11 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { const agentSafeBalance = useMemo( () => - services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data + services?.[0]?.chain_configs[CHAIN_CONFIG[ChainId.Optimism].middlewareChain].chain_data ?.multisig && walletBalances[ - services[0].chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data - .multisig! + services[0].chain_configs[CHAIN_CONFIG[ChainId.Optimism].middlewareChain].chain_data + .multisig! ], [services, walletBalances], ); diff --git a/frontend/context/StakingContractInfoProvider.tsx b/frontend/context/StakingContractInfoProvider.tsx index e023be78e..17dd4ce55 100644 --- a/frontend/context/StakingContractInfoProvider.tsx +++ b/frontend/context/StakingContractInfoProvider.tsx @@ -22,6 +22,7 @@ import { DEFAULT_STAKING_PROGRAM_ID, StakingProgramContext, } from './StakingProgramProvider'; +import { ChainId } from '@/enums/Chain'; type StakingContractInfoContextProps = { activeStakingContractInfo?: Partial; @@ -43,8 +44,8 @@ export const StakingContractInfoContext = isStakingContractInfoRecordLoaded: false, isActiveStakingContractInfoLoaded: false, stakingContractInfoRecord: undefined, - updateActiveStakingContractInfo: async () => {}, - setIsPaused: () => {}, + updateActiveStakingContractInfo: async () => { }, + setIsPaused: () => { }, }); export const StakingContractInfoProvider = ({ @@ -71,7 +72,7 @@ export const StakingContractInfoProvider = ({ const serviceId = useMemo( () => - services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.token, + services?.[0]?.chain_configs[CHAIN_CONFIG[ChainId.Optimism].middlewareChain].chain_data?.token, [services], ); diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index dcb78765c..3371c2f17 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -11,6 +11,7 @@ import { CHAIN_CONFIG } from '@/config/chains'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useServices } from '@/hooks/useServices'; import { AutonolasService } from '@/service/Autonolas'; +import { ChainId } from '@/enums/Chain'; export const INITIAL_DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.Beta; @@ -22,8 +23,8 @@ export const StakingProgramContext = createContext<{ }>({ activeStakingProgramId: undefined, defaultStakingProgramId: INITIAL_DEFAULT_STAKING_PROGRAM_ID, - updateActiveStakingProgramId: async () => {}, - setDefaultStakingProgramId: () => {}, + updateActiveStakingProgramId: async () => { }, + setDefaultStakingProgramId: () => { }, }); /** Determines the current active staking program, if any */ @@ -40,10 +41,10 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { const updateActiveStakingProgramId = useCallback(async () => { // if no service nft, not staked const serviceId = - service?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.token; + service?.chain_configs[CHAIN_CONFIG[ChainId.Optimism].middlewareChain].chain_data?.token; if ( - !service?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.token + !service?.chain_configs[CHAIN_CONFIG[ChainId.Optimism].middlewareChain].chain_data?.token ) { setActiveStakingProgramId(null); return; diff --git a/frontend/hooks/useAddress.ts b/frontend/hooks/useAddress.ts index d729957d4..e7895909e 100644 --- a/frontend/hooks/useAddress.ts +++ b/frontend/hooks/useAddress.ts @@ -1,17 +1,18 @@ import { CHAIN_CONFIG } from '@/config/chains'; import { useServices } from './useServices'; +import { ChainId } from '@/enums/Chain'; export const useAddress = () => { const { service } = useServices(); /** agent safe multisig address */ const multisigAddress = - service?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data?.multisig; + service?.chain_configs?.[CHAIN_CONFIG[ChainId.Optimism].middlewareChain]?.chain_data?.multisig; /** agent instance EOA address */ const instanceAddress = - service?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data + service?.chain_configs?.[CHAIN_CONFIG[ChainId.Optimism].middlewareChain]?.chain_data ?.instances?.[0]; return { instanceAddress, multisigAddress }; diff --git a/operate/operate_types.py b/operate/operate_types.py index 767e7729c..6e3199bf5 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -179,7 +179,6 @@ class LedgerConfig(LocalResource): """Ledger config.""" rpc: str - type: LedgerType chain: Chain diff --git a/operate/services/manage.py b/operate/services/manage.py index 1a498e113..0fc0b3055 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -135,7 +135,7 @@ def get_on_chain_manager(self, ledger_config: LedgerConfig) -> OnChainManager: """Get OnChainManager instance.""" return OnChainManager( rpc=ledger_config.rpc, - wallet=self.wallet_manager.load(ledger_config.type), + wallet=self.wallet_manager.load(ledger_config.chain.ledger_type), contracts=CONTRACTS[ledger_config.chain], ) @@ -143,7 +143,7 @@ def get_eth_safe_tx_builder(self, ledger_config: LedgerConfig) -> EthSafeTxBuild """Get EthSafeTxBuilder instance.""" return EthSafeTxBuilder( rpc=ledger_config.rpc, - wallet=self.wallet_manager.load(ledger_config.type), + wallet=self.wallet_manager.load(ledger_config.chain.ledger_type), contracts=CONTRACTS[ledger_config.chain], ) @@ -495,7 +495,7 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to user_params = chain_config.chain_data.user_params keys = service.keys instances = [key.address for key in keys] - wallet = self.wallet_manager.load(ledger_config.type) + wallet = self.wallet_manager.load(ledger_config.chain.ledger_type) sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config) safe = wallet.safes[Chain(chain)] # TODO fix this @@ -918,7 +918,7 @@ def _terminate_service_on_chain_from_safe( # pylint: disable=too-many-locals chain_data = chain_config.chain_data keys = service.keys instances = [key.address for key in keys] - wallet = self.wallet_manager.load(ledger_config.type) + wallet = self.wallet_manager.load(ledger_config.chain.ledger_type) safe = wallet.safes[Chain(chain)] # type: ignore # TODO fixme @@ -1332,7 +1332,7 @@ def fund_service_single_chain( # pylint: disable=too-many-arguments,too-many-lo chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data - wallet = self.wallet_manager.load(ledger_config.type) + wallet = self.wallet_manager.load(ledger_config.chain.ledger_type) ledger_api = wallet.ledger_api( chain=ledger_config.chain, rpc=rpc or ledger_config.rpc ) @@ -1399,7 +1399,7 @@ def fund_service_erc20( # pylint: disable=too-many-arguments,too-many-locals chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data - wallet = self.wallet_manager.load(ledger_config.type) + wallet = self.wallet_manager.load(ledger_config.chain.ledger_type) ledger_api = wallet.ledger_api( chain=ledger_config.chain, rpc=rpc or ledger_config.rpc ) diff --git a/operate/services/service.py b/operate/services/service.py index 8baa0e3ba..6606286e0 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -266,7 +266,6 @@ def ledger_configs(self) -> LedgerConfigs: ledger_configs[str(config["chain_id"])] = LedgerConfig( rpc=config["address"], chain=chain, - type=LedgerType.ETHEREUM, ) return ledger_configs @@ -565,7 +564,7 @@ def _build_host(self, force: bool = True, chain: t.Optional[str] = None) -> None ) # TODO: Support for multiledger builder.try_update_ledger_params( - chain=LedgerType(ledger_config.type).name.lower(), + chain=ledger_config.chain.ledger_type.name.lower(), address=ledger_config.rpc, ) @@ -788,12 +787,12 @@ def migrate_format(cls, path: Path) -> bool: new_chain_configs = {} for chain_id, chain_data in data["chain_configs"].items(): chain_data["ledger_config"]["chain"] = old_to_new_chains[chain_data["ledger_config"]["chain"]] - chain_data["ledger_config"]["type"] = old_to_new_ledgers[chain_data["ledger_config"]["type"]] + del chain_data["ledger_config"]["type"] new_chain_configs[Chain.from_id(int(chain_id)).value] = chain_data data["chain_configs"] = new_chain_configs - data["home_chain"] = Chain.from_id(int(data["home_chain"])).value - del data["home_chain"] + data["home_chain"] = Chain.from_id(int(data["home_chain_id"])).value + del data["home_chain_id"] if "env_variables" not in data: data["env_variables"] = {} From 43183b114488e6b0d0a45600772d29d20dfc492d Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 17:23:25 +0100 Subject: [PATCH 209/463] fix: add env variables when updating a service --- operate/services/service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/operate/services/service.py b/operate/services/service.py index 9685cc499..fee2a0214 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -946,6 +946,7 @@ def update( self.name = service_template["name"] self.hash = service_template["hash"] self.description = service_template["description"] + self.env_variables = service_template["env_variables"] # Only update hash_history if latest inserted hash is different if self.hash_history[max(self.hash_history.keys())] != service_template["hash"]: From eaa70e565061d901c1a3f64d927f1e44d9bae8bc Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 17:57:07 +0100 Subject: [PATCH 210/463] [no ci] fix: manage.py --- operate/services/manage.py | 45 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index a20ff505d..1a92a0519 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -532,28 +532,29 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to ) # TODO A customized, arbitrary computation mechanism should be devised. - env_var_to_value = { - "ETHEREUM_LEDGER_RPC": PUBLIC_RPCS[ChainType.ETHEREUM], - "GNOSIS_LEDGER_RPC": PUBLIC_RPCS[ChainType.GNOSIS], - "BASE_LEDGER_RPC": PUBLIC_RPCS[ChainType.BASE], - "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[ChainType.OPTIMISM], - "STAKING_CONTRACT_ADDRESS": staking_params.get("staking_contract"), - "MECH_ACTIVITY_CHECKER_CONTRACT": staking_params.get("activity_checker"), - "MECH_CONTRACT_ADDRESS": staking_params.get("agent_mech"), - "MECH_REQUEST_PRICE": "10000000000000000", - "USE_MECH_MARKETPLACE": str( - "mech_marketplace" - in service.chain_configs[ - service.home_chain_id - ].chain_data.user_params.staking_program_id - ), - "REQUESTER_STAKING_INSTANCE_ADDRESS": staking_params.get( - "staking_contract" - ), - "PRIORITY_MECH_ADDRESS": staking_params.get("agent_mech"), - } - - service.update_env_variables_values(env_var_to_value) + if chain_id == service.home_chain_id: + env_var_to_value = { + "ETHEREUM_LEDGER_RPC": PUBLIC_RPCS[ChainType.ETHEREUM], + "GNOSIS_LEDGER_RPC": PUBLIC_RPCS[ChainType.GNOSIS], + "BASE_LEDGER_RPC": PUBLIC_RPCS[ChainType.BASE], + "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[ChainType.OPTIMISM], + "STAKING_CONTRACT_ADDRESS": staking_params.get("staking_contract"), + "MECH_ACTIVITY_CHECKER_CONTRACT": staking_params.get("activity_checker"), + "MECH_CONTRACT_ADDRESS": staking_params.get("agent_mech"), + "MECH_REQUEST_PRICE": "10000000000000000", + "USE_MECH_MARKETPLACE": str( + "mech_marketplace" + in service.chain_configs[ + service.home_chain_id + ].chain_data.user_params.staking_program_id + ), + "REQUESTER_STAKING_INSTANCE_ADDRESS": staking_params.get( + "staking_contract" + ), + "PRIORITY_MECH_ADDRESS": staking_params.get("agent_mech"), + } + + service.update_env_variables_values(env_var_to_value) if user_params.use_staking: self.logger.info("Checking staking compatibility") From 7a42bf9c03c9dae52a69b1aed09c93aa8187c65b Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 18:38:41 +0100 Subject: [PATCH 211/463] chore: fix migrate --- operate/wallet/master.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/operate/wallet/master.py b/operate/wallet/master.py index fa0a1cf1f..71f5b8961 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -573,6 +573,9 @@ def migrate_wallet_configs(self) -> None: print(self.path) for ledger_type in LedgerType: + if not self.exists(ledger_type=ledger_type): + continue + wallet_class = LEDGER_TYPE_TO_WALLET_CLASS.get(ledger_type) if wallet_class is None: continue From e696e9f4196a11472476474ae0e591bd02c50f0d Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 19:08:49 +0100 Subject: [PATCH 212/463] chore: rename variables --- api.md | 6 +-- frontend/service/Wallet.ts | 6 +-- operate/cli.py | 59 +++++++++++++------------- operate/services/manage.py | 8 ++-- operate/wallet/master.py | 86 +++++++++++++++++++------------------- scripts/setup_wallet.py | 4 +- 6 files changed, 84 insertions(+), 85 deletions(-) diff --git a/api.md b/api.md index 650c1dfd4..7bcaec3e9 100644 --- a/api.md +++ b/api.md @@ -203,9 +203,9 @@ Creates a master wallet for given chain type. If a wallet already exists for a g
Request -```js +```json { - "chain_type": ChainType, + "chain": Chain, } ``` @@ -240,7 +240,7 @@ Creates a Gnosis safe for given chain type. ```js { - "chain_type": ChainType, + "chain": Chain, } ``` diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index b9224ec9f..42eb0efda 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -17,7 +17,7 @@ const createEoa = async (chain: MiddlewareChain) => headers: { ...CONTENT_TYPE_JSON_UTF8, }, - body: JSON.stringify({ chain_type: chain }), + body: JSON.stringify({ chain: chain }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create EOA'); @@ -29,7 +29,7 @@ const createSafe = async (chain: MiddlewareChain, owner?: string) => headers: { ...CONTENT_TYPE_JSON_UTF8, }, - body: JSON.stringify({ chain_type: chain, owner: owner }), + body: JSON.stringify({ chain: chain, owner: owner }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create safe'); @@ -41,7 +41,7 @@ const addBackupOwner = async (chain: MiddlewareChain, owner: string) => headers: { ...CONTENT_TYPE_JSON_UTF8, }, - body: JSON.stringify({ chain_type: chain, owner: owner }), + body: JSON.stringify({ chain: chain, owner: owner }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to add backup owner'); diff --git a/operate/cli.py b/operate/cli.py index 91a7b6407..12b695926 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -42,7 +42,7 @@ from operate import services from operate.account.user import UserAccount from operate.constants import KEY, KEYS, OPERATE, SERVICES -from operate.operate_types import Chain, DeploymentStatus +from operate.operate_types import Chain, LedgerType, DeploymentStatus from operate.services.health_checker import HealthChecker from operate.wallet.master import MasterWalletManager @@ -435,8 +435,7 @@ async def _create_wallet(request: Request) -> t.List[t.Dict]: ) data = await request.json() - chain_type = Chain(data["chain_type"]) - ledger_type = chain_type.ledger_type + ledger_type = LedgerType(data["ledger_type"]) manager = operate.wallet_manager if manager.exists(ledger_type=ledger_type): return JSONResponse( @@ -464,8 +463,8 @@ async def _get_safes(request: Request) -> t.List[t.Dict]: @with_retries async def _get_safe(request: Request) -> t.List[t.Dict]: """Create wallet safe""" - chain_type = Chain.from_string(request.path_params["chain"]) - ledger_type = chain_type.ledger_type + chain = Chain.from_string(request.path_params["chain"]) + ledger_type = chain.ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse( @@ -473,12 +472,12 @@ async def _get_safe(request: Request) -> t.List[t.Dict]: status_code=404, ) safes = manager.load(ledger_type=ledger_type).safes - if safes is None or safes.get(chain_type) is None: + if safes is None or safes.get(chain) is None: return JSONResponse(content={"error": "No safes found"}) return JSONResponse( content={ - "safe": safes[chain_type], + "safe": safes[chain], }, ) @@ -499,34 +498,34 @@ async def _create_safe(request: Request) -> t.List[t.Dict]: ) data = await request.json() - chain_type = Chain(data["chain_type"]) - ledger_type = chain_type.ledger_type + chain = Chain(data["chain"]) + ledger_type = chain.ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse(content={"error": "Wallet does not exist"}) wallet = manager.load(ledger_type=ledger_type) - if wallet.safes is not None and wallet.safes.get(chain_type) is not None: + if wallet.safes is not None and wallet.safes.get(chain) is not None: return JSONResponse( content={ - "safe": wallet.safes.get(chain_type), - "message": f"Safe already exists {chain_type=}.", + "safe": wallet.safes.get(chain), + "message": f"Safe already exists {chain=}.", } ) safes = t.cast(t.Dict[Chain, str], wallet.safes) wallet.create_safe( # pylint: disable=no-member - chain_type=chain_type, + chain=chain, owner=data.get("owner"), ) wallet.transfer( - to=t.cast(str, safes.get(chain_type)), + to=t.cast(str, safes.get(chain)), amount=int(1e18), - chain_type=chain_type, + chain=chain, from_safe=False, ) return JSONResponse( - content={"safe": safes.get(chain_type), "message": "Safe created!"} + content={"safe": safes.get(chain), "message": "Safe created!"} ) @app.post("/api/wallet/safes") @@ -546,37 +545,37 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: ) data = await request.json() - chain_types = [Chain(chain_type) for chain_type in data["chain_types"]] + chains = [Chain(chain_str) for chain_str in data["chains"]] # check that all chains are supported - for chain_type in chain_types: - ledger_type = chain_type.ledger_type + for chain in chains: + ledger_type = chain.ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse( content={ - "error": f"Wallet does not exist for chain_type {chain_type}" + "error": f"Wallet does not exist for chain {chain}" } ) # mint the safes - for chain_type in chain_types: - ledger_type = chain_type.ledger_type + for chain in chains: + ledger_type = chain.ledger_type manager = operate.wallet_manager wallet = manager.load(ledger_type=ledger_type) - if wallet.safes is not None and wallet.safes.get(chain_type) is not None: - logger.info(f"Safe already exists for chain_type {chain_type}") + if wallet.safes is not None and wallet.safes.get(chain) is not None: + logger.info(f"Safe already exists for chain {chain}") continue safes = t.cast(t.Dict[Chain, str], wallet.safes) wallet.create_safe( # pylint: disable=no-member - chain_type=chain_type, + chain=chain, owner=data.get("owner"), ) wallet.transfer( - to=t.cast(str, safes.get(chain_type)), + to=t.cast(str, safes.get(chain)), amount=int(1e18), - chain_type=chain_type, + chain=chain, from_safe=False, ) @@ -600,15 +599,15 @@ async def _update_safe(request: Request) -> t.List[t.Dict]: ) data = await request.json() - chain_type = Chain(data["chain_type"]) - ledger_type = chain_type.ledger_type + chain = Chain(data["chain"]) + ledger_type = chain.ledger_type manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse(content={"error": "Wallet does not exist"}) wallet = manager.load(ledger_type=ledger_type) wallet.add_or_swap_owner( - chain_type=chain_type, + chain=chain, owner=data.get("owner"), ) return JSONResponse(content=wallet.json) diff --git a/operate/services/manage.py b/operate/services/manage.py index ed4545bcd..0d5d7a0d3 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -1359,7 +1359,7 @@ def fund_service_single_chain( # pylint: disable=too-many-arguments,too-many-lo wallet.transfer( to=key.address, amount=int(to_transfer), - chain_type=ledger_config.chain, + chain=ledger_config.chain, from_safe=from_safe, rpc=rpc or ledger_config.rpc, ) @@ -1379,7 +1379,7 @@ def fund_service_single_chain( # pylint: disable=too-many-arguments,too-many-lo wallet.transfer( to=t.cast(str, chain_data.multisig), amount=int(to_transfer), - chain_type=ledger_config.chain, + chain=ledger_config.chain, rpc=rpc or ledger_config.rpc, ) @@ -1422,7 +1422,7 @@ def fund_service_erc20( # pylint: disable=too-many-arguments,too-many-locals token=token, to=key.address, amount=int(to_transfer), - chain_type=ledger_config.chain, + chain=ledger_config.chain, from_safe=from_safe, rpc=rpc or ledger_config.rpc, ) @@ -1447,7 +1447,7 @@ def fund_service_erc20( # pylint: disable=too-many-arguments,too-many-locals token=token, to=t.cast(str, chain_data.multisig), amount=int(to_transfer), - chain_type=ledger_config.chain, + chain=ledger_config.chain, rpc=rpc or ledger_config.rpc, ) diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 71f5b8961..2203ef547 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -102,7 +102,7 @@ def transfer( self, to: str, amount: int, - chain_type: Chain, + chain: Chain, from_safe: bool = True, rpc: t.Optional[str] = None, ) -> None: @@ -115,7 +115,7 @@ def transfer_erc20( token: str, to: str, amount: int, - chain_type: Chain, + chain: Chain, from_safe: bool = True, rpc: t.Optional[str] = None, ) -> None: @@ -129,7 +129,7 @@ def new(password: str, path: Path) -> t.Tuple["MasterWallet", t.List[str]]: def create_safe( self, - chain_type: Chain, + chain: Chain, owner: t.Optional[str] = None, rpc: t.Optional[str] = None, ) -> None: @@ -138,7 +138,7 @@ def create_safe( def add_backup_owner( self, - chain_type: Chain, + chain: Chain, owner: str, rpc: t.Optional[str] = None, ) -> None: @@ -147,7 +147,7 @@ def add_backup_owner( def swap_backup_owner( self, - chain_type: Chain, + chain: Chain, old_owner: str, new_owner: str, rpc: t.Optional[str] = None, @@ -157,7 +157,7 @@ def swap_backup_owner( def add_or_swap_owner( self, - chain_type: Chain, + chain: Chain, owner: str, rpc: t.Optional[str] = None, ) -> None: @@ -187,11 +187,11 @@ class EthereumMasterWallet(MasterWallet): _crypto_cls = EthereumCrypto def _transfer_from_eoa( - self, to: str, amount: int, chain_type: Chain, rpc: t.Optional[str] = None + self, to: str, amount: int, chain: Chain, rpc: t.Optional[str] = None ) -> None: """Transfer funds from EOA wallet.""" ledger_api = t.cast( - EthereumApi, self.ledger_api(chain=chain_type, rpc=rpc) + EthereumApi, self.ledger_api(chain=chain, rpc=rpc) ) tx_helper = TxSettler( ledger_api=ledger_api, @@ -214,7 +214,7 @@ def _build_tx( # pylint: disable=unused-argument amount=amount, tx_fee=50000, tx_nonce="0x", - chain_id=chain_type.id, + chain_id=chain.id, raise_on_try=True, max_fee_per_gas=int(max_fee_per_gas) if max_fee_per_gas else None, max_priority_fee_per_gas=int(max_priority_fee_per_gas) @@ -230,14 +230,14 @@ def _build_tx( # pylint: disable=unused-argument tx_helper.transact(lambda x: x, "", kwargs={}) def _transfer_from_safe( - self, to: str, amount: int, chain_type: Chain, rpc: t.Optional[str] = None + self, to: str, amount: int, chain: Chain, rpc: t.Optional[str] = None ) -> None: """Transfer funds from safe wallet.""" if self.safes is not None: transfer_from_safe( - ledger_api=self.ledger_api(chain=chain_type, rpc=rpc), + ledger_api=self.ledger_api(chain=chain, rpc=rpc), crypto=self.crypto, - safe=t.cast(str, self.safes[chain_type]), + safe=t.cast(str, self.safes[chain]), to=to, amount=amount, ) @@ -249,15 +249,15 @@ def _transfer_erc20_from_safe( token: str, to: str, amount: int, - chain_type: Chain, + chain: Chain, rpc: t.Optional[str] = None, ) -> None: """Transfer funds from safe wallet.""" transfer_erc20_from_safe( - ledger_api=self.ledger_api(chain=chain_type, rpc=rpc), + ledger_api=self.ledger_api(chain=chain, rpc=rpc), crypto=self.crypto, token=token, - safe=t.cast(str, self.safes[chain_type]), # type: ignore + safe=t.cast(str, self.safes[chain]), # type: ignore to=to, amount=amount, ) @@ -266,7 +266,7 @@ def transfer( self, to: str, amount: int, - chain_type: Chain, + chain: Chain, from_safe: bool = True, rpc: t.Optional[str] = None, ) -> None: @@ -275,13 +275,13 @@ def transfer( return self._transfer_from_safe( to=to, amount=amount, - chain_type=chain_type, + chain=chain, rpc=rpc, ) return self._transfer_from_eoa( to=to, amount=amount, - chain_type=chain_type, + chain=chain, rpc=rpc, ) @@ -291,7 +291,7 @@ def transfer_erc20( token: str, to: str, amount: int, - chain_type: Chain, + chain: Chain, from_safe: bool = True, rpc: t.Optional[str] = None, ) -> None: @@ -302,7 +302,7 @@ def transfer_erc20( token=token, to=to, amount=amount, - chain_type=chain_type, + chain=chain, rpc=rpc, ) @@ -334,36 +334,36 @@ def new( def create_safe( self, - chain_type: Chain, + chain: Chain, owner: t.Optional[str] = None, rpc: t.Optional[str] = None, ) -> None: """Create safe.""" - if chain_type in self.safe_chains: + if chain in self.safe_chains: return safe, self.safe_nonce = create_gnosis_safe( - ledger_api=self.ledger_api(chain=chain_type, rpc=rpc), + ledger_api=self.ledger_api(chain=chain, rpc=rpc), crypto=self.crypto, owner=owner, salt_nonce=self.safe_nonce, ) - self.safe_chains.append(chain_type) + self.safe_chains.append(chain) if self.safes is None: self.safes = {} - self.safes[chain_type] = safe + self.safes[chain] = safe self.store() def add_backup_owner( self, - chain_type: Chain, + chain: Chain, owner: str, rpc: t.Optional[str] = None, ) -> None: """Add a backup owner.""" - ledger_api = self.ledger_api(chain=chain_type, rpc=rpc) - if chain_type not in self.safes: # type: ignore - raise ValueError(f"Safes not created for chain_type {chain_type}!") - safe = t.cast(str, self.safes[chain_type]) # type: ignore + ledger_api = self.ledger_api(chain=chain, rpc=rpc) + if chain not in self.safes: # type: ignore + raise ValueError(f"Safes not created for chain {chain}!") + safe = t.cast(str, self.safes[chain]) # type: ignore if len(get_owners(ledger_api=ledger_api, safe=safe)) == 2: raise ValueError("Backup owner already exist!") add_owner( @@ -375,16 +375,16 @@ def add_backup_owner( def swap_backup_owner( self, - chain_type: Chain, + chain: Chain, old_owner: str, new_owner: str, rpc: t.Optional[str] = None, ) -> None: """Swap backup owner.""" - ledger_api = self.ledger_api(chain=chain_type, rpc=rpc) - if chain_type not in self.safes: # type: ignore - raise ValueError(f"Safes not created for chain_type {chain_type}!") - safe = t.cast(str, self.safes[chain_type]) # type: ignore + ledger_api = self.ledger_api(chain=chain, rpc=rpc) + if chain not in self.safes: # type: ignore + raise ValueError(f"Safes not created for chain {chain}!") + safe = t.cast(str, self.safes[chain]) # type: ignore if len(get_owners(ledger_api=ledger_api, safe=safe)) == 1: raise ValueError("Backup owner does not exist, cannot swap!") swap_owner( @@ -397,18 +397,18 @@ def swap_backup_owner( def add_or_swap_owner( self, - chain_type: Chain, + chain: Chain, owner: str, rpc: t.Optional[str] = None, ) -> None: """Add or swap backup owner.""" - ledger_api = self.ledger_api(chain=chain_type, rpc=rpc) - if self.safes is None or chain_type not in self.safes: - raise ValueError(f"Safes not created for chain_type {chain_type}!") - safe = t.cast(str, self.safes[chain_type]) + ledger_api = self.ledger_api(chain=chain, rpc=rpc) + if self.safes is None or chain not in self.safes: + raise ValueError(f"Safes not created for chain {chain}!") + safe = t.cast(str, self.safes[chain]) owners = get_owners(ledger_api=ledger_api, safe=safe) if len(owners) == 1: - return self.add_backup_owner(chain_type=chain_type, owner=owner, rpc=rpc) + return self.add_backup_owner(chain=chain, owner=owner, rpc=rpc) owners.remove(self.address) (old_owner,) = owners @@ -416,7 +416,7 @@ def add_or_swap_owner( return None return self.swap_backup_owner( - chain_type=chain_type, + chain=chain, old_owner=old_owner, new_owner=owner, rpc=rpc, @@ -426,7 +426,7 @@ def add_or_swap_owner( def load(cls, path: Path) -> "EthereumMasterWallet": """Load master wallet.""" # TODO: This is a complex way to read the 'safes' dictionary. - # The reason for that is that wallet.safes[chain_type] would fail + # The reason for that is that wallet.safes[chain] would fail # (for example in service manager) when passed a ChainType key. raw_ethereum_wallet = t.cast(EthereumMasterWallet, super().load(path)) # type: ignore diff --git a/scripts/setup_wallet.py b/scripts/setup_wallet.py index 78336f6df..99279ae16 100644 --- a/scripts/setup_wallet.py +++ b/scripts/setup_wallet.py @@ -48,7 +48,7 @@ wallet = requests.post( "http://localhost:8000/api/wallet", json={ - "chain_type": Chain.GNOSIS, + "chain": Chain.GNOSIS, }, ).json() print("Setting up wallet") @@ -61,7 +61,7 @@ requests.post( "http://localhost:8000/api/wallet/safe", json={ - "chain_type": Chain.GNOSIS, + "chain": Chain.GNOSIS, "owner": "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC", # Backup owner }, ).json() From 80449bcb03c9e4f934082cef272d8eae29c13da7 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 21:09:28 +0100 Subject: [PATCH 213/463] fix: chain id --- operate/services/service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operate/services/service.py b/operate/services/service.py index c18162e02..4eea55f98 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -262,8 +262,8 @@ def ledger_configs(self) -> LedgerConfigs: ): for _, config in override["config"]["ledger_apis"].items(): # TODO chain name is inferred from the chain_id. The actual id provided on service.yaml is ignored. - chain = Chain.from_id(chain_id=config["chain_id"]) - ledger_configs[str(config["chain_id"])] = LedgerConfig( + chain = Chain.from_id(chain_id=config["chain_id"]) # type: ignore + ledger_configs[chain.value] = LedgerConfig( rpc=config["address"], chain=chain, ) From 69c420ca18ac66d69eaf894b11e0b79eb07e95fc Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 21:13:21 +0100 Subject: [PATCH 214/463] fix: rename if migration fails --- operate/services/manage.py | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/operate/services/manage.py b/operate/services/manage.py index 0d5d7a0d3..77a1f788f 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -1581,14 +1581,26 @@ def migrate_service_configs(self) -> None: paths = list(self.path.iterdir()) for path in paths: - if path.name.startswith(DELETE_PREFIX): - shutil.rmtree(path) - self.logger.info(f"Deleted folder: {path.name}") - - if path.name.startswith(SERVICE_CONFIG_PREFIX) or path.name.startswith( - "bafybei" - ): - self.logger.info(f"migrate_service_configs {str(path)}") - migrated = Service.migrate_format(path) - if migrated: - self.logger.info(f"Folder {str(path)} has been migrated.") + try: + if path.name.startswith(DELETE_PREFIX): + shutil.rmtree(path) + self.logger.info(f"Deleted folder: {path.name}") + + if path.name.startswith(SERVICE_CONFIG_PREFIX) or path.name.startswith( + "bafybei" + ): + self.logger.info(f"migrate_service_configs {str(path)}") + migrated = Service.migrate_format(path) + if migrated: + self.logger.info(f"Folder {str(path)} has been migrated.") + except Exception: # pylint: disable=broad-except + self.logger.error( + f"Failed to migrate service: {path.name}. Exception: {traceback.format_exc()}" + ) + # rename the invalid path + timestamp = int(time.time()) + invalid_path = path.parent / f"invalid_{timestamp}_{path.name}" + os.rename(path, invalid_path) + self.logger.info( + f"Renamed invalid service: {path.name} to {invalid_path.name}" + ) From 5adab412f5f333fa880f042228b70382791bc47b Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 21:15:41 +0100 Subject: [PATCH 215/463] fix: service config version (version 4 has not been released) --- operate/services/service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operate/services/service.py b/operate/services/service.py index 4eea55f98..7a2c2f43d 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -97,7 +97,7 @@ ALL_PARTICIPANTS = "all_participants" CONSENSUS_THRESHOLD = "consensus_threshold" DELETE_PREFIX = "delete_" -SERVICE_CONFIG_VERSION = 5 +SERVICE_CONFIG_VERSION = 4 SERVICE_CONFIG_PREFIX = "sc-" DUMMY_MULTISIG = "0xm" @@ -797,7 +797,7 @@ def migrate_format(cls, path: Path) -> bool: if "env_variables" not in data: data["env_variables"] = {} - data["version"] = 5 + data["version"] = SERVICE_CONFIG_VERSION with open(path / Service._file, "w", encoding="utf-8") as file: json.dump(data, file, indent=2) From 33414163232fcfe1ca0fef8f057f7de078cf057c Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 22:32:03 +0100 Subject: [PATCH 216/463] fix: migration --- operate/services/service.py | 46 +++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/operate/services/service.py b/operate/services/service.py index 7a2c2f43d..9f381af94 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -79,7 +79,6 @@ EnvVariables, LedgerConfig, LedgerConfigs, - LedgerType, OnChainData, OnChainState, OnChainUserParams, @@ -688,6 +687,14 @@ def migrate_format(cls, path: Path) -> bool: ): return False + if path.name.startswith("bafybei"): + backup_name = f"backup_{int(time.time())}_{path.name}" + backup_path = path.parent / backup_name + shutil.copytree(path, backup_path) + deployment_path = backup_path / 'deployment' + if deployment_path.is_dir(): + shutil.rmtree(deployment_path) + with open(path / Service._file, "r", encoding="utf-8") as file: data = json.load(file) @@ -706,9 +713,9 @@ def migrate_format(cls, path: Path) -> bool: "version": 2, "hash": data.get("hash"), "keys": data.get("keys"), - "home_chain": "gnosis", # Assuming a default value for home_chain + "home_chain_id": "100", # This is the default value for version 2 - do not change, will be corrected below "chain_configs": { - "gnosis": { + "100": { # This is the default value for version 2 - do not change, will be corrected below "ledger_config": { "rpc": data.get("ledger_config", {}).get("rpc"), "type": data.get("ledger_config", {}).get("type"), @@ -741,6 +748,9 @@ def migrate_format(cls, path: Path) -> bool: "fund_requirements": data.get("chain_data", {}) .get("user_params", {}) .get("fund_requirements", {}), + "agent_id": data.get("chain_data", {}) + .get("user_params", {}) + .get("agent_id", "14"), }, }, } @@ -765,19 +775,7 @@ def migrate_format(cls, path: Path) -> bool: service_config_id = Service.get_new_service_config_id(path) new_path = path.parent / service_config_id data["service_config_id"] = service_config_id - - service_path = Path(data["service_path"]) - if service_path.exists() and service_path.is_dir(): - shutil.rmtree(service_path) - path = path.rename(new_path) - service_path = Path( - IPFSTool().download( - hash_id=data["hash"], - target_dir=path, - ) - ) - data["service_path"] = str(service_path) old_to_new_ledgers = ["ethereum", "solana"] for key_data in data["keys"]: @@ -788,10 +786,10 @@ def migrate_format(cls, path: Path) -> bool: for chain_id, chain_data in data["chain_configs"].items(): chain_data["ledger_config"]["chain"] = old_to_new_chains[chain_data["ledger_config"]["chain"]] del chain_data["ledger_config"]["type"] - new_chain_configs[Chain.from_id(int(chain_id)).value] = chain_data + new_chain_configs[Chain.from_id(int(chain_id)).value] = chain_data # type: ignore data["chain_configs"] = new_chain_configs - data["home_chain"] = Chain.from_id(int(data["home_chain_id"])).value + data["home_chain"] = data.setdefault("home_chain", Chain.from_id(int(data.get("home_chain_id", "100"))).value) # type: ignore del data["home_chain_id"] if "env_variables" not in data: @@ -799,6 +797,20 @@ def migrate_format(cls, path: Path) -> bool: data["version"] = SERVICE_CONFIG_VERSION + # Redownload service path + service_path = path / Path(data["service_path"]).name + if service_path.exists() and service_path.is_dir(): + print("EXISTS") + shutil.rmtree(service_path) + + service_path = Path( + IPFSTool().download( + hash_id=data["hash"], + target_dir=path, + ) + ) + data["service_path"] = str(service_path) + with open(path / Service._file, "w", encoding="utf-8") as file: json.dump(data, file, indent=2) From fd64dd4b689c728206a4dae89c9cc052a1afb108 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 22:32:51 +0100 Subject: [PATCH 217/463] fix: linters --- operate/cli.py | 6 ++---- operate/operate_types.py | 19 +++++++++++-------- operate/services/manage.py | 8 ++++++-- operate/services/service.py | 22 ++++++++++++++++------ operate/wallet/master.py | 14 ++++++++++---- 5 files changed, 45 insertions(+), 24 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index 12b695926..73ef05353 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -42,7 +42,7 @@ from operate import services from operate.account.user import UserAccount from operate.constants import KEY, KEYS, OPERATE, SERVICES -from operate.operate_types import Chain, LedgerType, DeploymentStatus +from operate.operate_types import Chain, DeploymentStatus, LedgerType from operate.services.health_checker import HealthChecker from operate.wallet.master import MasterWalletManager @@ -552,9 +552,7 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse( - content={ - "error": f"Wallet does not exist for chain {chain}" - } + content={"error": f"Wallet does not exist for chain {chain}"} ) # mint the safes diff --git a/operate/operate_types.py b/operate/operate_types.py index 6e3199bf5..e3c8e1101 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -21,9 +21,9 @@ import enum import os -from types import MethodType import typing as t from dataclasses import dataclass +from types import MethodType from autonomy.chain.config import ChainType from autonomy.chain.constants import CHAIN_NAME_TO_CHAIN_ID @@ -43,8 +43,7 @@ CHAIN_NAME_TO_CHAIN_ID["solana"] = 900 _CHAIN_ID_TO_CHAIN_NAME = { - chain_id: chain_name - for chain_name, chain_id in CHAIN_NAME_TO_CHAIN_ID.items() + chain_id: chain_name for chain_name, chain_id in CHAIN_NAME_TO_CHAIN_ID.items() } @@ -74,10 +73,14 @@ def from_id(cls, chain_id: int) -> "LedgerType": # TODO: Migrate this to open-autonomy and remove this modified version of Chain here and use the one from open-autonomy # This version of open-autonomy must support the LedgerType to support SOLANA in the future # If solana support is not fuly implemented, decide to keep this half-baked feature -Chain = enum.Enum('Chain', [(member.name, member.value) for member in ChainType] + [ - ('MODE', 'mode'), # TODO: update open-autonomy version and remove this - ('SOLANA', 'solana'), -]) +Chain = enum.Enum( + "Chain", + [(member.name, member.value) for member in ChainType] + + [ + ("MODE", "mode"), # TODO: update open-autonomy version and remove this + ("SOLANA", "solana"), + ], +) class ChainMixin: @@ -120,7 +123,7 @@ def from_id(cls, chain_id: int) -> "Chain": # Add the ChainMixin methods to the Chain enum for name in dir(ChainMixin): - if not name.startswith('__'): + if not name.startswith("__"): setattr(Chain, name, getattr(ChainMixin, name)) diff --git a/operate/services/manage.py b/operate/services/manage.py index 77a1f788f..096f8ff2e 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -538,7 +538,9 @@ def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,to "BASE_LEDGER_RPC": PUBLIC_RPCS[Chain.BASE], "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[Chain.OPTIMISTIC], "STAKING_CONTRACT_ADDRESS": staking_params.get("staking_contract"), - "MECH_ACTIVITY_CHECKER_CONTRACT": staking_params.get("activity_checker"), + "MECH_ACTIVITY_CHECKER_CONTRACT": staking_params.get( + "activity_checker" + ), "MECH_CONTRACT_ADDRESS": staking_params.get("agent_mech"), "MECH_REQUEST_PRICE": "10000000000000000", "USE_MECH_MARKETPLACE": str( @@ -1505,7 +1507,9 @@ def deploy_service_locally( service = self.load(service_config_id=service_config_id) deployment = service.deployment - deployment.build(use_docker=use_docker, force=force, chain=chain or service.home_chain) + deployment.build( + use_docker=use_docker, force=force, chain=chain or service.home_chain + ) deployment.start(use_docker=use_docker) return deployment diff --git a/operate/services/service.py b/operate/services/service.py index 9f381af94..1e953eb81 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -70,9 +70,9 @@ from operate.keys import Keys from operate.operate_http.exceptions import NotAllowed from operate.operate_types import ( + Chain, ChainConfig, ChainConfigs, - Chain, DeployedNodes, DeploymentConfig, DeploymentStatus, @@ -691,7 +691,7 @@ def migrate_format(cls, path: Path) -> bool: backup_name = f"backup_{int(time.time())}_{path.name}" backup_path = path.parent / backup_name shutil.copytree(path, backup_path) - deployment_path = backup_path / 'deployment' + deployment_path = backup_path / "deployment" if deployment_path.is_dir(): shutil.rmtree(deployment_path) @@ -781,13 +781,23 @@ def migrate_format(cls, path: Path) -> bool: for key_data in data["keys"]: key_data["ledger"] = old_to_new_ledgers[key_data["ledger"]] - old_to_new_chains = ["ethereum", "goerli", "gnosis", "solana", "optimistic", "base", "mode"] + old_to_new_chains = [ + "ethereum", + "goerli", + "gnosis", + "solana", + "optimistic", + "base", + "mode", + ] new_chain_configs = {} for chain_id, chain_data in data["chain_configs"].items(): - chain_data["ledger_config"]["chain"] = old_to_new_chains[chain_data["ledger_config"]["chain"]] + chain_data["ledger_config"]["chain"] = old_to_new_chains[ + chain_data["ledger_config"]["chain"] + ] del chain_data["ledger_config"]["type"] new_chain_configs[Chain.from_id(int(chain_id)).value] = chain_data # type: ignore - + data["chain_configs"] = new_chain_configs data["home_chain"] = data.setdefault("home_chain", Chain.from_id(int(data.get("home_chain_id", "100"))).value) # type: ignore del data["home_chain_id"] @@ -802,7 +812,7 @@ def migrate_format(cls, path: Path) -> bool: if service_path.exists() and service_path.is_dir(): print("EXISTS") shutil.rmtree(service_path) - + service_path = Path( IPFSTool().download( hash_id=data["hash"], diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 2203ef547..30fd975b6 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -190,9 +190,7 @@ def _transfer_from_eoa( self, to: str, amount: int, chain: Chain, rpc: t.Optional[str] = None ) -> None: """Transfer funds from EOA wallet.""" - ledger_api = t.cast( - EthereumApi, self.ledger_api(chain=chain, rpc=rpc) - ) + ledger_api = t.cast(EthereumApi, self.ledger_api(chain=chain, rpc=rpc)) tx_helper = TxSettler( ledger_api=ledger_api, crypto=self.crypto, @@ -453,7 +451,15 @@ def migrate_format(cls, path: Path) -> bool: data["safes"] = safes migrated = True - old_to_new_chains = ["ethereum", "goerli", "gnosis", "solana", "optimistic", "base", "mode"] + old_to_new_chains = [ + "ethereum", + "goerli", + "gnosis", + "solana", + "optimistic", + "base", + "mode", + ] safe_chains = [] for chain in data["safe_chains"]: if isinstance(chain, int): From 4a4d50123c4a05af24f2094eea5de8c02c36a07d Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 14 Nov 2024 22:35:48 +0100 Subject: [PATCH 218/463] fix: linters --- operate/operate_types.py | 1 - operate/services/manage.py | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/operate/operate_types.py b/operate/operate_types.py index e3c8e1101..26002611e 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -23,7 +23,6 @@ import os import typing as t from dataclasses import dataclass -from types import MethodType from autonomy.chain.config import ChainType from autonomy.chain.constants import CHAIN_NAME_TO_CHAIN_ID diff --git a/operate/services/manage.py b/operate/services/manage.py index 096f8ff2e..387aabf9e 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -110,9 +110,9 @@ def _get_all_services(self) -> t.List[Service]: raise e except Exception as e: # pylint: disable=broad-except self.logger.error( - f"Failed to load service: {path.name}. Exception: {traceback.format_exc()}" + f"Failed to load service: {path.name}. Exception {e}: {traceback.format_exc()}" ) - # rename the invalid path + # Rename the invalid path timestamp = int(time.time()) invalid_path = path.parent / f"invalid_{timestamp}_{path.name}" os.rename(path, invalid_path) @@ -1597,11 +1597,11 @@ def migrate_service_configs(self) -> None: migrated = Service.migrate_format(path) if migrated: self.logger.info(f"Folder {str(path)} has been migrated.") - except Exception: # pylint: disable=broad-except + except Exception as e: # pylint: disable=broad-except self.logger.error( - f"Failed to migrate service: {path.name}. Exception: {traceback.format_exc()}" + f"Failed to migrate service: {path.name}. Exception {e}: {traceback.format_exc()}" ) - # rename the invalid path + # Rename the invalid path timestamp = int(time.time()) invalid_path = path.parent / f"invalid_{timestamp}_{path.name}" os.rename(path, invalid_path) From 43d0e787b1a41e957b6e7f1c205be35ea887edb5 Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Fri, 15 Nov 2024 20:48:46 +0530 Subject: [PATCH 219/463] Refactor: Override ledger address from a env var Signed-off-by: OjusWiZard --- frontend/constants/serviceTemplates.ts | 6 ++++ operate/services/service.py | 48 -------------------------- 2 files changed, 6 insertions(+), 48 deletions(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 0b500f71f..6dbb4956f 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -96,6 +96,12 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ description: "", value: "", provision_type: EnvProvisionType.COMPUTED + }, + LEDGER_RPC_ADDRESS: { + name: "Address of Ethereum ledger connection", + description: "", + value: "https://virtual.gnosis.rpc.tenderly.co/0b10c83b-3fe8-4a39-aaac-93784a13541b", + provision_type: EnvProvisionType.FIXED } }, }, diff --git a/operate/services/service.py b/operate/services/service.py index 1e953eb81..b75ac3a26 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -146,42 +146,6 @@ def remove_service_network(service_name: str, force: bool = True) -> None: class ServiceBuilder(BaseServiceBuilder): """Service builder patch.""" - def try_update_ledger_params(self, chain: str, address: str) -> None: - """Try to update the ledger params.""" - - for override in deepcopy(self.service.overrides): - ( - override, - component_id, - _, - ) = self.service.process_metadata( - configuration=override, - ) - - if ( - component_id.package_type == PackageType.CONNECTION - and component_id.name == "ledger" - ): - ledger_connection_overrides = deepcopy(override) - break - else: - return - - # TODO: Support for multiple overrides - ledger_connection_overrides["config"]["ledger_apis"][chain]["address"] = address - service_overrides = deepcopy(self.service.overrides) - service_overrides = [ - override - for override in service_overrides - if override["public_id"] != str(component_id.public_id) - or override["type"] != PackageType.CONNECTION.value - ] - - ledger_connection_overrides["type"] = PackageType.CONNECTION.value - ledger_connection_overrides["public_id"] = str(component_id.public_id) - service_overrides.append(ledger_connection_overrides) - self.service.overrides = service_overrides - def try_update_runtime_params( self, multisig_address: t.Optional[str] = None, @@ -440,7 +404,6 @@ def _build_docker( chain = service.home_chain chain_config = service.chain_configs[chain] - ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data builder.try_update_runtime_params( @@ -449,11 +412,6 @@ def _build_docker( service_id=chain_data.token, consensus_threshold=None, ) - # TODO: Support for multiledger - builder.try_update_ledger_params( - chain=chain, - address=ledger_config.rpc, - ) # build deployment ( @@ -528,7 +486,6 @@ def _build_host(self, force: bool = True, chain: t.Optional[str] = None) -> None chain = service.home_chain chain_config = service.chain_configs[chain] - ledger_config = chain_config.ledger_config chain_data = chain_config.chain_data keys_file = self.path / KEYS_JSON @@ -561,11 +518,6 @@ def _build_host(self, force: bool = True, chain: t.Optional[str] = None) -> None service_id=chain_data.token, consensus_threshold=None, ) - # TODO: Support for multiledger - builder.try_update_ledger_params( - chain=ledger_config.chain.ledger_type.name.lower(), - address=ledger_config.rpc, - ) ( HostDeploymentGenerator( From b106186cdbd498676557a376da49f3dd404d1d42 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 15 Nov 2024 18:14:46 +0100 Subject: [PATCH 220/463] chore: fix templates --- frontend/constants/serviceTemplates.ts | 6 ---- templates/trader.yaml | 41 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 6dbb4956f..0b500f71f 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -96,12 +96,6 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ description: "", value: "", provision_type: EnvProvisionType.COMPUTED - }, - LEDGER_RPC_ADDRESS: { - name: "Address of Ethereum ledger connection", - description: "", - value: "https://virtual.gnosis.rpc.tenderly.co/0b10c83b-3fe8-4a39-aaac-93784a13541b", - provision_type: EnvProvisionType.FIXED } }, }, diff --git a/templates/trader.yaml b/templates/trader.yaml index cf639bf46..cf3c82e0d 100644 --- a/templates/trader.yaml +++ b/templates/trader.yaml @@ -17,3 +17,44 @@ configurations: fund_requirements: agent: 100000000000000000 safe: 5000000000000000000 +env_variables: + GNOSIS_LEDGER_RPC: + name: "Gnosis ledger RPC" + description: "" + value: "" + provision_type: "computed" + STAKING_CONTRACT_ADDRESS: + name: "Staking contract address" + description: "" + value: "" + provision_type: "computed" + MECH_ACTIVITY_CHECKER_CONTRACT: + name: "Mech activity checker contract" + description: "" + value: "" + provision_type: "computed" + MECH_CONTRACT_ADDRESS: + name: "Mech contract address" + description: "" + value: "" + provision_type: "computed" + MECH_REQUEST_PRICE: + name: "Mech request price" + description: "" + value: "" + provision_type: "computed" + USE_MECH_MARKETPLACE: + name: "Use Mech marketplace" + description: "" + value: "" + provision_type: "computed" + REQUESTER_STAKING_INSTANCE_ADDRESS: + name: "Requester staking instance address" + description: "" + value: "" + provision_type: "computed" + PRIORITY_MECH_ADDRESS: + name: "Priority Mech address" + description: "" + value: "" + provision_type: "computed" From 797097db09623f12c524788ee010d883f38d68e7 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Sat, 16 Nov 2024 14:09:41 +0100 Subject: [PATCH 221/463] chore: add tests --- operate/services/service.py | 3 + poetry.lock | 38 ++++- pyproject.toml | 1 + tests/test_service_migration.py | 277 ++++++++++++++++++++++++++++++++ tests/test_wallet_migration.py | 20 +++ 5 files changed, 333 insertions(+), 6 deletions(-) create mode 100644 tests/test_service_migration.py create mode 100644 tests/test_wallet_migration.py diff --git a/operate/services/service.py b/operate/services/service.py index b75ac3a26..6037f24ad 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -717,6 +717,9 @@ def migrate_format(cls, path: Path) -> bool: chain_data.setdefault("chain_data", {}).setdefault( "user_params", {} ).setdefault("use_mech_marketplace", False) + chain_data.setdefault("chain_data", {}).setdefault( + "user_params", {} + ).setdefault("agent_id", 14) data["description"] = data.setdefault("description", data.get("name")) data["hash_history"] = data.setdefault( diff --git a/poetry.lock b/poetry.lock index 5fce400d8..fa2061054 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiohttp" @@ -959,6 +959,24 @@ toolz = ">=0.8.0" [package.extras] cython = ["cython"] +[[package]] +name = "deepdiff" +version = "8.0.1" +description = "Deep Difference and Search of any Python object/data. Recreate objects by adding adding deltas to each other." +optional = false +python-versions = ">=3.8" +files = [ + {file = "deepdiff-8.0.1-py3-none-any.whl", hash = "sha256:42e99004ce603f9a53934c634a57b04ad5900e0d8ed0abb15e635767489cbc05"}, + {file = "deepdiff-8.0.1.tar.gz", hash = "sha256:245599a4586ab59bb599ca3517a9c42f3318ff600ded5e80a3432693c8ec3c4b"}, +] + +[package.dependencies] +orderly-set = "5.2.2" + +[package.extras] +cli = ["click (==8.1.7)", "pyyaml (==6.0.1)"] +optimize = ["orjson"] + [[package]] name = "distlib" version = "0.3.8" @@ -1971,10 +1989,7 @@ py-multicodec = ">=0.2.0" pymultihash = "0.8.2" pytest = {version = ">=7.0.0,<7.3.0", optional = true, markers = "extra == \"all\""} python-dotenv = ">=0.14.0,<1.0.1" -pyyaml = [ - {version = ">=6.0.1,<7"}, - {version = ">=6.0.1,<9", optional = true, markers = "extra == \"all\""}, -] +pyyaml = {version = ">=6.0.1,<7", optional = true, markers = "extra == \"all\""} requests = ">=2.28.1,<3" semver = ">=2.9.1,<3.0.0" @@ -2101,6 +2116,17 @@ werkzeug = "2.0.3" all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.53.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.53.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +[[package]] +name = "orderly-set" +version = "5.2.2" +description = "Orderly set" +optional = false +python-versions = ">=3.8" +files = [ + {file = "orderly_set-5.2.2-py3-none-any.whl", hash = "sha256:f7a37c95a38c01cdfe41c3ffb62925a318a2286ea0a41790c057fc802aec54da"}, + {file = "orderly_set-5.2.2.tar.gz", hash = "sha256:52a18b86aaf3f5d5a498bbdb27bf3253a4e5c57ab38e5b7a56fa00115cd28448"}, +] + [[package]] name = "packaging" version = "23.2" @@ -3477,4 +3503,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "<3.12,>=3.9" -content-hash = "85568473089af1d5ba1b5a8ada225c96b7ff03067a2edabdaacd7ff61e4d0a06" +content-hash = "0c3dee80f18869f08b05c0cb56897d158e201cd4e0e4baacaa84954eac63dcea" diff --git a/pyproject.toml b/pyproject.toml index cb5374184..def9463c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,6 +48,7 @@ web3 = "==6.1.0" psutil = "^5.9.8" pyinstaller = "^6.8.0" aiohttp = "3.9.5" +deepdiff = "^8.0.1" [tool.poetry.group.development.dependencies] tomte = {version = "0.2.17", extras = ["cli"]} diff --git a/tests/test_service_migration.py b/tests/test_service_migration.py new file mode 100644 index 000000000..994858a6f --- /dev/null +++ b/tests/test_service_migration.py @@ -0,0 +1,277 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests for services.service module.""" + +import json +import typing as t +from pathlib import Path + +import pytest +from deepdiff import DeepDiff + +from operate.services.service import SERVICE_CONFIG_PREFIX, Service + + +SERVICE_CONFIG_ID_PLACEHOLDER = "sc-00000000-0000-0000-0000-000000000000" +TIMESTAMP_PLACEHOLDER = 1704063600 + + +def config_json_data_v0(use_staking: bool = True, **kwargs) -> t.Dict[str, t.Any]: + return { + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "keys": [ + { + "ledger": 0, + "address": "0x0000000000000000000000000000000000000000", + "private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", + } + ], + "ledger_config": {"rpc": "https://rpc", "type": 0, "chain": 2}, + "chain_data": { + "instances": ["0x0000000000000000000000000000000000000001"], + "token": 101, + "multisig": "0x0000000000000000000000000000000000000002", + "staked": True, + "on_chain_state": 4, + "user_params": { + "nft": "bafybei0000000000000000000000000000000000000000000000000001", + "agent_id": 14, + "threshold": 1, + "use_staking": use_staking, + "cost_of_bond": 10000000000000000, + "olas_cost_of_bond": 10000000000000000000, + "olas_required_to_stake": 10000000000000000000, + "fund_requirements": { + "agent": 100000000000000000, + "safe": 5000000000000000000, + }, + }, + }, + "service_path": "/home/user/.operate/services/bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u/trader_pearl", + "name": "Trader", + } + + +def config_json_data_v2(use_staking: bool = True, **kwargs) -> t.Dict[str, t.Any]: + return { + "version": 2, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "keys": [ + { + "ledger": 0, + "address": "0x0000000000000000000000000000000000000000", + "private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", + } + ], + "home_chain_id": "100", + "chain_configs": { + "100": { + "ledger_config": {"rpc": "https://rpc", "type": 0, "chain": 2}, + "chain_data": { + "instances": ["0x0000000000000000000000000000000000000001"], + "token": 101, + "multisig": "0x0000000000000000000000000000000000000002", + "staked": True, + "on_chain_state": 4, + "user_params": { + "staking_program_id": "pearl_alpha", # TODO use a different program and change reference_data dynamically on the test. + "nft": "bafybei0000000000000000000000000000000000000000000000000001", + "threshold": 1, + "use_staking": use_staking, + "cost_of_bond": 10000000000000000, + "fund_requirements": { + "agent": 100000000000000000, + "safe": 5000000000000000000, + }, + }, + }, + } + }, + "service_path": "/home/user/.operate/services/bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u/trader_pearl", + "name": "Trader", + } + + +def config_json_data_v3( + use_staking: bool = True, use_mech_marketplace: bool = True, **kwargs +) -> t.Dict[str, t.Any]: + return { + "version": 3, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "keys": [ + { + "ledger": 0, + "address": "0x0000000000000000000000000000000000000000", + "private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", + } + ], + "home_chain_id": "100", + "chain_configs": { + "100": { + "ledger_config": {"rpc": "https://rpc", "type": 0, "chain": 2}, + "chain_data": { + "instances": ["0x0000000000000000000000000000000000000001"], + "token": 101, + "multisig": "0x0000000000000000000000000000000000000002", + "staked": True, + "on_chain_state": 4, + "user_params": { + "staking_program_id": "pearl_alpha", # TODO use a different program and change reference_data dynamically on the test. + "nft": "bafybei0000000000000000000000000000000000000000000000000001", + "threshold": 1, + "use_staking": use_staking, + "use_mech_marketplace": use_mech_marketplace, + "cost_of_bond": 10000000000000000, + "fund_requirements": { + "agent": 100000000000000000, + "safe": 5000000000000000000, + }, + }, + }, + } + }, + "service_path": "/home/user/.operate/services/bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u/trader_pearl", + "name": "Trader", + } + + +def get_expected_data( # pylint: disable=too-many-arguments + version: int = 4, + service_config_id: str = "sc-00000000-0000-0000-0000-000000000000", + service_path: str = "/home/user/.operate/services/sc-00000000-0000-0000-0000-000000000000/trader_pearl", + token: int = 101, + staked: bool = True, + on_chain_state: int = 4, + use_staking: bool = True, + use_mech_marketplace: bool = False, + cost_of_bond: int = 10000000000000000, + agent_fund: int = 100000000000000000, + safe_fund: int = 5000000000000000000, + hash_timestamp: int = 1704063600, + threshold: int = 1, + agent_id: int = 14, + staking_program_id: str = "pearl_alpha", +) -> t.Dict[str, t.Any]: + return { + "version": version, + "service_config_id": service_config_id, + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "hash_history": { + hash_timestamp: "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u" + }, + "keys": [ + { + "ledger": "ethereum", + "address": "0x0000000000000000000000000000000000000000", + "private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", + } + ], + "home_chain": "gnosis", + "chain_configs": { + "gnosis": { + "ledger_config": {"rpc": "https://rpc", "chain": "gnosis"}, + "chain_data": { + "instances": ["0x0000000000000000000000000000000000000001"], + "token": token, + "multisig": "0x0000000000000000000000000000000000000002", + "staked": staked, + "on_chain_state": on_chain_state, + "user_params": { + "staking_program_id": staking_program_id, + "nft": "bafybei0000000000000000000000000000000000000000000000000001", + "threshold": threshold, + "agent_id": agent_id, + "use_staking": use_staking, + "use_mech_marketplace": use_mech_marketplace, + "cost_of_bond": cost_of_bond, + "fund_requirements": { + "agent": agent_fund, + "safe": safe_fund, + }, + }, + }, + } + }, + "description": "Trader", + "env_variables": {}, + "service_path": service_path, + "name": "Trader", + } + + +class TestService: + """Tests for services.service.Service class.""" + + @pytest.mark.parametrize( + "config_json_data_func, use_staking, use_mech_marketplace", + [ + (config_json_data_v0, True, False), + (config_json_data_v2, True, False), + (config_json_data_v3, True, False), + ], + ) + def test_service_migrate_format( + self, + config_json_data_func: t.Callable[..., t.Dict[str, t.Any]], + use_staking: bool, + use_mech_marketplace: bool, + tmp_path: Path, + ): + """Test services.service.Service.migrate_format()""" + + config_json_data = config_json_data_func( + use_staking=use_staking, use_mech_marketplace=use_mech_marketplace + ) + service_config_dir = ( + tmp_path / "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u" + ) + service_config_dir.mkdir(parents=True, exist_ok=True) + + # Write the config_json_data data to config.json + config_json_path = service_config_dir / "config.json" + with open(config_json_path, "w", encoding="utf-8") as file: + json.dump(config_json_data, file, indent=4) + + # Migrate the service using Service.migrate_format + Service.migrate_format(service_config_dir) + + # Locate the new path (directory starting with 'sc-') + new_config_dir = next(tmp_path.glob(f"{SERVICE_CONFIG_PREFIX}*/")) + new_config_json_path = new_config_dir / "config.json" + + # Read the resulting config.json + with open(new_config_json_path, "r", encoding="utf-8") as file: + migrated_data = json.load(file) + migrated_data["hash_history"] = { + TIMESTAMP_PLACEHOLDER: list(migrated_data["hash_history"].values())[0] + } + + expected_data = get_expected_data( + use_staking=use_staking, + use_mech_marketplace=use_mech_marketplace, + service_config_id=new_config_dir.name, + service_path=str(new_config_dir / "trader_pearl"), + ) + + diff = DeepDiff(expected_data, migrated_data) + if diff: + print(diff) + + assert not diff, "Migrated data does not match expected data." diff --git a/tests/test_wallet_migration.py b/tests/test_wallet_migration.py new file mode 100644 index 000000000..53b7a4b7b --- /dev/null +++ b/tests/test_wallet_migration.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Test for wallet.master module.""" From 03f3fe015455a28fd2bd1312d12df207a0d405c5 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Sun, 17 Nov 2024 18:52:06 +0100 Subject: [PATCH 222/463] chore: tests --- tests/test_service_migration.py | 277 ---------------- tests/test_services_service.py | 304 ++++++++++++++++++ ...let_migration.py => test_wallet_master.py} | 0 3 files changed, 304 insertions(+), 277 deletions(-) delete mode 100644 tests/test_service_migration.py create mode 100644 tests/test_services_service.py rename tests/{test_wallet_migration.py => test_wallet_master.py} (100%) diff --git a/tests/test_service_migration.py b/tests/test_service_migration.py deleted file mode 100644 index 994858a6f..000000000 --- a/tests/test_service_migration.py +++ /dev/null @@ -1,277 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------------------------ -# -# Copyright 2024 Valory AG -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# ------------------------------------------------------------------------------ - -"""Tests for services.service module.""" - -import json -import typing as t -from pathlib import Path - -import pytest -from deepdiff import DeepDiff - -from operate.services.service import SERVICE_CONFIG_PREFIX, Service - - -SERVICE_CONFIG_ID_PLACEHOLDER = "sc-00000000-0000-0000-0000-000000000000" -TIMESTAMP_PLACEHOLDER = 1704063600 - - -def config_json_data_v0(use_staking: bool = True, **kwargs) -> t.Dict[str, t.Any]: - return { - "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", - "keys": [ - { - "ledger": 0, - "address": "0x0000000000000000000000000000000000000000", - "private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", - } - ], - "ledger_config": {"rpc": "https://rpc", "type": 0, "chain": 2}, - "chain_data": { - "instances": ["0x0000000000000000000000000000000000000001"], - "token": 101, - "multisig": "0x0000000000000000000000000000000000000002", - "staked": True, - "on_chain_state": 4, - "user_params": { - "nft": "bafybei0000000000000000000000000000000000000000000000000001", - "agent_id": 14, - "threshold": 1, - "use_staking": use_staking, - "cost_of_bond": 10000000000000000, - "olas_cost_of_bond": 10000000000000000000, - "olas_required_to_stake": 10000000000000000000, - "fund_requirements": { - "agent": 100000000000000000, - "safe": 5000000000000000000, - }, - }, - }, - "service_path": "/home/user/.operate/services/bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u/trader_pearl", - "name": "Trader", - } - - -def config_json_data_v2(use_staking: bool = True, **kwargs) -> t.Dict[str, t.Any]: - return { - "version": 2, - "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", - "keys": [ - { - "ledger": 0, - "address": "0x0000000000000000000000000000000000000000", - "private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", - } - ], - "home_chain_id": "100", - "chain_configs": { - "100": { - "ledger_config": {"rpc": "https://rpc", "type": 0, "chain": 2}, - "chain_data": { - "instances": ["0x0000000000000000000000000000000000000001"], - "token": 101, - "multisig": "0x0000000000000000000000000000000000000002", - "staked": True, - "on_chain_state": 4, - "user_params": { - "staking_program_id": "pearl_alpha", # TODO use a different program and change reference_data dynamically on the test. - "nft": "bafybei0000000000000000000000000000000000000000000000000001", - "threshold": 1, - "use_staking": use_staking, - "cost_of_bond": 10000000000000000, - "fund_requirements": { - "agent": 100000000000000000, - "safe": 5000000000000000000, - }, - }, - }, - } - }, - "service_path": "/home/user/.operate/services/bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u/trader_pearl", - "name": "Trader", - } - - -def config_json_data_v3( - use_staking: bool = True, use_mech_marketplace: bool = True, **kwargs -) -> t.Dict[str, t.Any]: - return { - "version": 3, - "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", - "keys": [ - { - "ledger": 0, - "address": "0x0000000000000000000000000000000000000000", - "private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", - } - ], - "home_chain_id": "100", - "chain_configs": { - "100": { - "ledger_config": {"rpc": "https://rpc", "type": 0, "chain": 2}, - "chain_data": { - "instances": ["0x0000000000000000000000000000000000000001"], - "token": 101, - "multisig": "0x0000000000000000000000000000000000000002", - "staked": True, - "on_chain_state": 4, - "user_params": { - "staking_program_id": "pearl_alpha", # TODO use a different program and change reference_data dynamically on the test. - "nft": "bafybei0000000000000000000000000000000000000000000000000001", - "threshold": 1, - "use_staking": use_staking, - "use_mech_marketplace": use_mech_marketplace, - "cost_of_bond": 10000000000000000, - "fund_requirements": { - "agent": 100000000000000000, - "safe": 5000000000000000000, - }, - }, - }, - } - }, - "service_path": "/home/user/.operate/services/bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u/trader_pearl", - "name": "Trader", - } - - -def get_expected_data( # pylint: disable=too-many-arguments - version: int = 4, - service_config_id: str = "sc-00000000-0000-0000-0000-000000000000", - service_path: str = "/home/user/.operate/services/sc-00000000-0000-0000-0000-000000000000/trader_pearl", - token: int = 101, - staked: bool = True, - on_chain_state: int = 4, - use_staking: bool = True, - use_mech_marketplace: bool = False, - cost_of_bond: int = 10000000000000000, - agent_fund: int = 100000000000000000, - safe_fund: int = 5000000000000000000, - hash_timestamp: int = 1704063600, - threshold: int = 1, - agent_id: int = 14, - staking_program_id: str = "pearl_alpha", -) -> t.Dict[str, t.Any]: - return { - "version": version, - "service_config_id": service_config_id, - "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", - "hash_history": { - hash_timestamp: "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u" - }, - "keys": [ - { - "ledger": "ethereum", - "address": "0x0000000000000000000000000000000000000000", - "private_key": "0x0000000000000000000000000000000000000000000000000000000000000000", - } - ], - "home_chain": "gnosis", - "chain_configs": { - "gnosis": { - "ledger_config": {"rpc": "https://rpc", "chain": "gnosis"}, - "chain_data": { - "instances": ["0x0000000000000000000000000000000000000001"], - "token": token, - "multisig": "0x0000000000000000000000000000000000000002", - "staked": staked, - "on_chain_state": on_chain_state, - "user_params": { - "staking_program_id": staking_program_id, - "nft": "bafybei0000000000000000000000000000000000000000000000000001", - "threshold": threshold, - "agent_id": agent_id, - "use_staking": use_staking, - "use_mech_marketplace": use_mech_marketplace, - "cost_of_bond": cost_of_bond, - "fund_requirements": { - "agent": agent_fund, - "safe": safe_fund, - }, - }, - }, - } - }, - "description": "Trader", - "env_variables": {}, - "service_path": service_path, - "name": "Trader", - } - - -class TestService: - """Tests for services.service.Service class.""" - - @pytest.mark.parametrize( - "config_json_data_func, use_staking, use_mech_marketplace", - [ - (config_json_data_v0, True, False), - (config_json_data_v2, True, False), - (config_json_data_v3, True, False), - ], - ) - def test_service_migrate_format( - self, - config_json_data_func: t.Callable[..., t.Dict[str, t.Any]], - use_staking: bool, - use_mech_marketplace: bool, - tmp_path: Path, - ): - """Test services.service.Service.migrate_format()""" - - config_json_data = config_json_data_func( - use_staking=use_staking, use_mech_marketplace=use_mech_marketplace - ) - service_config_dir = ( - tmp_path / "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u" - ) - service_config_dir.mkdir(parents=True, exist_ok=True) - - # Write the config_json_data data to config.json - config_json_path = service_config_dir / "config.json" - with open(config_json_path, "w", encoding="utf-8") as file: - json.dump(config_json_data, file, indent=4) - - # Migrate the service using Service.migrate_format - Service.migrate_format(service_config_dir) - - # Locate the new path (directory starting with 'sc-') - new_config_dir = next(tmp_path.glob(f"{SERVICE_CONFIG_PREFIX}*/")) - new_config_json_path = new_config_dir / "config.json" - - # Read the resulting config.json - with open(new_config_json_path, "r", encoding="utf-8") as file: - migrated_data = json.load(file) - migrated_data["hash_history"] = { - TIMESTAMP_PLACEHOLDER: list(migrated_data["hash_history"].values())[0] - } - - expected_data = get_expected_data( - use_staking=use_staking, - use_mech_marketplace=use_mech_marketplace, - service_config_id=new_config_dir.name, - service_path=str(new_config_dir / "trader_pearl"), - ) - - diff = DeepDiff(expected_data, migrated_data) - if diff: - print(diff) - - assert not diff, "Migrated data does not match expected data." diff --git a/tests/test_services_service.py b/tests/test_services_service.py new file mode 100644 index 000000000..66a3d535a --- /dev/null +++ b/tests/test_services_service.py @@ -0,0 +1,304 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------------------------ +# +# Copyright 2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +"""Tests for services.service module.""" + +import json +import typing as t +from pathlib import Path + +import pytest +from deepdiff import DeepDiff + +from operate.services.service import ( + SERVICE_CONFIG_PREFIX, + SERVICE_CONFIG_VERSION, + Service, +) + + +DEFAULT_CONFIG_KWARGS = { + "hash": "bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u", + "use_staking": True, + "use_mech_marketplace": False, + "rpc": "https://rpc.com", + "service_config_id": "sc-00000000-0000-0000-0000-000000000000", + "hash_timestamp": 1704063600, + "token": 42, + "staked": True, + "on_chain_state": 4, + "staking_program_id": "staking_program_1", + "threshold": 1, + "agent_id": 14, + "cost_of_bond": 10000000000000000, + "fund_requirements_agent": 100000000000000000, + "fund_requirements_safe": 5000000000000000000, + "nft": "bafybeinft", + "name": "Trader Service", + "description": "Service description", + "keys_address_0": "0x0000000000000000000000000000000000000001", + "keys_private_key_0": "0x0000000000000000000000000000000000000000000000000000000000000001", + "instance_0": "0x0000000000000000000000000000000000000001", + "multisig": "0x0000000000000000000000000000000000000020", +} + + +def get_config_json_data_v0(**kwargs) -> t.Dict[str, t.Any]: + """get_config_json_data_v0""" + + return { + "hash": kwargs.get("hash"), + "keys": [ + { + "ledger": 0, + "address": kwargs.get("keys_address_0"), + "private_key": kwargs.get("keys_private_key_0"), + } + ], + "ledger_config": {"rpc": kwargs.get("rpc"), "type": 0, "chain": 2}, + "chain_data": { + "instances": [kwargs.get("instance_0")], + "token": kwargs.get("token"), + "multisig": kwargs.get("multisig"), + "staked": True, + "on_chain_state": kwargs.get("on_chain_state"), + "user_params": { + "nft": kwargs.get("nft"), + "agent_id": kwargs.get("agent_id"), + "threshold": kwargs.get("threshold"), + "use_staking": kwargs.get("use_staking"), + "cost_of_bond": 10000000000000000, + "olas_cost_of_bond": 10000000000000000000, + "olas_required_to_stake": 10000000000000000000, + "fund_requirements": { + "agent": kwargs.get("fund_requirements_agent"), + "safe": kwargs.get("fund_requirements_safe"), + }, + }, + }, + "service_path": f"/home/user/.operate/services/{kwargs.get('hash')}/trader_pearl", + "name": kwargs.get("name"), + } + + +def get_config_json_data_v2(**kwargs) -> t.Dict[str, t.Any]: + """get_config_json_data_v2""" + + return { + "version": 2, + "hash": kwargs.get("hash"), + "keys": [ + { + "ledger": 0, + "address": kwargs.get("keys_address_0"), + "private_key": kwargs.get("keys_private_key_0"), + } + ], + "home_chain_id": "100", + "chain_configs": { + "100": { + "ledger_config": {"rpc": kwargs.get("rpc"), "type": 0, "chain": 2}, + "chain_data": { + "instances": [kwargs.get("instance_0")], + "token": kwargs.get("token"), + "multisig": kwargs.get("multisig"), + "staked": True, + "on_chain_state": kwargs.get("on_chain_state"), + "user_params": { + "staking_program_id": kwargs.get("staking_program_id"), + "nft": kwargs.get("nft"), + "threshold": kwargs.get("threshold"), + "use_staking": kwargs.get("use_staking"), + "cost_of_bond": 10000000000000000, + "fund_requirements": { + "agent": kwargs.get("fund_requirements_agent"), + "safe": kwargs.get("fund_requirements_safe"), + }, + }, + }, + } + }, + "service_path": f"/home/user/.operate/services/{kwargs.get('hash')}/trader_pearl", + "name": kwargs.get("name"), + } + + +def get_config_json_data_v3(**kwargs) -> t.Dict[str, t.Any]: + """get_config_json_data_v3""" + + return { + "version": 3, + "hash": kwargs.get("hash"), + "keys": [ + { + "ledger": 0, + "address": kwargs.get("keys_address_0"), + "private_key": kwargs.get("keys_private_key_0"), + } + ], + "home_chain_id": "100", + "chain_configs": { + "100": { + "ledger_config": {"rpc": kwargs.get("rpc"), "type": 0, "chain": 2}, + "chain_data": { + "instances": [kwargs.get("instance_0")], + "token": kwargs.get("token"), + "multisig": kwargs.get("multisig"), + "staked": True, + "on_chain_state": kwargs.get("on_chain_state"), + "user_params": { + "staking_program_id": kwargs.get("staking_program_id"), + "nft": kwargs.get("nft"), + "threshold": kwargs.get("threshold"), + "use_staking": kwargs.get("use_staking"), + "use_mech_marketplace": kwargs.get("use_mech_marketplace"), + "cost_of_bond": 10000000000000000, + "fund_requirements": { + "agent": kwargs.get("fund_requirements_agent"), + "safe": kwargs.get("fund_requirements_safe"), + }, + }, + }, + } + }, + "service_path": f"/home/user/.operate/services/{kwargs.get('hash')}/trader_pearl", + "name": kwargs.get("name"), + } + + +def get_config_json_data_v4(**kwargs) -> t.Dict[str, t.Any]: + """get_config_json_data_v4""" + + return { + "version": kwargs.get("version"), + "service_config_id": kwargs.get("service_config_id"), + "hash": kwargs.get("hash"), + "hash_history": {kwargs.get("hash_timestamp"): kwargs.get("hash")}, + "keys": [ + { + "ledger": "ethereum", + "address": kwargs.get("keys_address_0"), + "private_key": kwargs.get("keys_private_key_0"), + } + ], + "home_chain": "gnosis", + "chain_configs": { + "gnosis": { + "ledger_config": {"rpc": kwargs.get("rpc"), "chain": "gnosis"}, + "chain_data": { + "instances": [kwargs.get("instance_0")], + "token": kwargs.get("token"), + "multisig": kwargs.get("multisig"), + "staked": kwargs.get("staked"), + "on_chain_state": kwargs.get("on_chain_state"), + "user_params": { + "staking_program_id": kwargs.get("staking_program_id"), + "nft": kwargs.get("nft"), + "threshold": kwargs.get("threshold"), + "agent_id": kwargs.get("agent_id"), + "use_staking": kwargs.get("use_staking"), + "use_mech_marketplace": kwargs.get("use_mech_marketplace"), + "cost_of_bond": kwargs.get("cost_of_bond"), + "fund_requirements": { + "agent": kwargs.get("fund_requirements_agent"), + "safe": kwargs.get("fund_requirements_safe"), + }, + }, + }, + } + }, + "description": kwargs.get("description"), + "env_variables": {}, + "service_path": kwargs.get("service_path"), + "name": kwargs.get("name"), + } + + +get_expected_data = get_config_json_data_v4 + + +class TestService: + """Tests for services.service.Service class.""" + + @pytest.mark.parametrize( + "staking_program_id", ["staking_program_1", "staking_program_2"] + ) + @pytest.mark.parametrize("use_mech_marketplace", [True, False]) + @pytest.mark.parametrize("use_staking", [True, False]) + @pytest.mark.parametrize( + "get_config_json_data", + [get_config_json_data_v0, get_config_json_data_v2, get_config_json_data_v3], + ) + def test_service_migrate_format( + self, + get_config_json_data: t.Callable[..., t.Dict[str, t.Any]], + use_staking: bool, + use_mech_marketplace: bool, + staking_program_id: str, + tmp_path: Path, + ): + """Test services.service.Service.migrate_format()""" + + config_kwargs = DEFAULT_CONFIG_KWARGS.copy() + config_kwargs["use_staking"] = use_staking + config_kwargs["use_mech_marketplace"] = use_mech_marketplace + config_kwargs["staking_program"] = staking_program_id + old_config_json_data = get_config_json_data(**config_kwargs) + + # Emulate an existing service directory contents + service_config_dir = tmp_path / old_config_json_data.get( + "service_config_id", old_config_json_data.get("hash") + ) + service_config_dir.mkdir(parents=True, exist_ok=True) + + config_json_path = service_config_dir / "config.json" + with open(config_json_path, "w", encoding="utf-8") as file: + json.dump(old_config_json_data, file, indent=4) + + # Migrate the service using Service.migrate_format and read the resulting + # migrated data + Service.migrate_format(service_config_dir) + + migrated_config_dir = next(tmp_path.glob(f"{SERVICE_CONFIG_PREFIX}*/")) + new_config_json_path = migrated_config_dir / "config.json" + with open(new_config_json_path, "r", encoding="utf-8") as file: + migrated_data = json.load(file) + + # Construct the expected data + if old_config_json_data.get("version", 0) < 2: + config_kwargs["staking_program_id"] = "pearl_alpha" + + if old_config_json_data.get("version", 0) < 3: + config_kwargs["use_mech_marketplace"] = False + + if old_config_json_data.get("version", 0) < 4: + config_kwargs["description"] = config_kwargs["name"] + + config_kwargs["service_config_id"] = migrated_config_dir.name + config_kwargs["version"] = SERVICE_CONFIG_VERSION + config_kwargs["hash_timestamp"] = list(migrated_data["hash_history"].keys())[0] + config_kwargs["service_path"] = str(migrated_config_dir / "trader_pearl") + + expected_data = get_expected_data(**config_kwargs) + + diff = DeepDiff(migrated_data, expected_data) + if diff: + print(diff) + + assert not diff, "Migrated data does not match expected data." diff --git a/tests/test_wallet_migration.py b/tests/test_wallet_master.py similarity index 100% rename from tests/test_wallet_migration.py rename to tests/test_wallet_master.py From aa0079674ee029937e26e7f1932dc2b7d2dafa9f Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Mon, 18 Nov 2024 10:31:26 +0100 Subject: [PATCH 223/463] chore: add github actions --- .github/workflows/backend.yml | 20 ++++++++++++++++++++ operate/services/service.py | 3 +-- tests/test_services_service.py | 6 +++--- tox.ini | 7 +++++++ 4 files changed, 31 insertions(+), 5 deletions(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index 242e2e8bb..ba15f9370 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -39,3 +39,23 @@ jobs: # Run backend # - run: yarn dev:backend + + unit-tests: + continue-on-error: True + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ ubuntu-latest ] + python-version: [ "3.9", "3.10", "3.11" ] + + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + + - name: Run unit tests + run: tox -e unit-tests diff --git a/operate/services/service.py b/operate/services/service.py index 6037f24ad..3af20fe83 100644 --- a/operate/services/service.py +++ b/operate/services/service.py @@ -29,7 +29,7 @@ import time import typing as t import uuid -from copy import copy, deepcopy +from copy import copy from dataclasses import dataclass from json import JSONDecodeError from pathlib import Path @@ -42,7 +42,6 @@ PRIVATE_KEY_PATH_SCHEMA, SKILL, ) -from aea.configurations.data_types import PackageType from aea.helpers.yaml_utils import yaml_dump, yaml_load, yaml_load_all from aea_cli_ipfs.ipfs_utils import IPFSTool from autonomy.cli.helpers.deployment import run_deployment, stop_deployment diff --git a/tests/test_services_service.py b/tests/test_services_service.py index 66a3d535a..e8bc29d83 100644 --- a/tests/test_services_service.py +++ b/tests/test_services_service.py @@ -83,7 +83,7 @@ def get_config_json_data_v0(**kwargs) -> t.Dict[str, t.Any]: "agent_id": kwargs.get("agent_id"), "threshold": kwargs.get("threshold"), "use_staking": kwargs.get("use_staking"), - "cost_of_bond": 10000000000000000, + "cost_of_bond": kwargs.get("cost_of_bond"), "olas_cost_of_bond": 10000000000000000000, "olas_required_to_stake": 10000000000000000000, "fund_requirements": { @@ -125,7 +125,7 @@ def get_config_json_data_v2(**kwargs) -> t.Dict[str, t.Any]: "nft": kwargs.get("nft"), "threshold": kwargs.get("threshold"), "use_staking": kwargs.get("use_staking"), - "cost_of_bond": 10000000000000000, + "cost_of_bond": kwargs.get("cost_of_bond"), "fund_requirements": { "agent": kwargs.get("fund_requirements_agent"), "safe": kwargs.get("fund_requirements_safe"), @@ -168,7 +168,7 @@ def get_config_json_data_v3(**kwargs) -> t.Dict[str, t.Any]: "threshold": kwargs.get("threshold"), "use_staking": kwargs.get("use_staking"), "use_mech_marketplace": kwargs.get("use_mech_marketplace"), - "cost_of_bond": 10000000000000000, + "cost_of_bond": kwargs.get("cost_of_bond"), "fund_requirements": { "agent": kwargs.get("fund_requirements_agent"), "safe": kwargs.get("fund_requirements_safe"), diff --git a/tox.ini b/tox.ini index 259bb9ba8..8d6426723 100644 --- a/tox.ini +++ b/tox.ini @@ -219,3 +219,10 @@ ignore_missing_imports = True [mypy-eth_utils.*] ignore_missing_imports = True + +[testenv:unit-tests] +allowlist_externals = poetry +commands_pre = + poetry install +commands = + poetry run pytest tests/ \ No newline at end of file From d71df20704d69c15a55525ec60709b614b299601 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Mon, 18 Nov 2024 11:13:10 +0100 Subject: [PATCH 224/463] chore: update workflow --- .github/workflows/backend.yml | 20 -------------------- .github/workflows/common_checks.yml | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 20 deletions(-) diff --git a/.github/workflows/backend.yml b/.github/workflows/backend.yml index ba15f9370..242e2e8bb 100644 --- a/.github/workflows/backend.yml +++ b/.github/workflows/backend.yml @@ -39,23 +39,3 @@ jobs: # Run backend # - run: yarn dev:backend - - unit-tests: - continue-on-error: True - runs-on: ${{ matrix.os }} - - strategy: - matrix: - os: [ ubuntu-latest ] - python-version: [ "3.9", "3.10", "3.11" ] - - timeout-minutes: 30 - - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-python@v3 - with: - python-version: ${{ matrix.python-version }} - - - name: Run unit tests - run: tox -e unit-tests diff --git a/.github/workflows/common_checks.yml b/.github/workflows/common_checks.yml index df38258ba..a90183604 100644 --- a/.github/workflows/common_checks.yml +++ b/.github/workflows/common_checks.yml @@ -48,3 +48,25 @@ jobs: # - name: License compatibility check # run: tox -e liccheck # tox -p -e vulture -e darglint + + test: + continue-on-error: True + needs: + - linter_checks + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ ubuntu-latest ] + python-version: [ "3.9", "3.10", "3.11" ] + + timeout-minutes: 30 + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + + - name: Run unit tests + run: tox -e unit-tests From 790e6a37d09a53f6bbb1235082083ac888bfae14 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Mon, 18 Nov 2024 12:03:13 +0100 Subject: [PATCH 225/463] fix: linters --- tests/test_services_service.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_services_service.py b/tests/test_services_service.py index e8bc29d83..c2461e755 100644 --- a/tests/test_services_service.py +++ b/tests/test_services_service.py @@ -23,8 +23,8 @@ import typing as t from pathlib import Path -import pytest -from deepdiff import DeepDiff +import pytest # type: ignore +from deepdiff import DeepDiff # type: ignore from operate.services.service import ( SERVICE_CONFIG_PREFIX, @@ -59,7 +59,7 @@ } -def get_config_json_data_v0(**kwargs) -> t.Dict[str, t.Any]: +def get_config_json_data_v0(**kwargs: t.Any) -> t.Dict[str, t.Any]: """get_config_json_data_v0""" return { @@ -97,7 +97,7 @@ def get_config_json_data_v0(**kwargs) -> t.Dict[str, t.Any]: } -def get_config_json_data_v2(**kwargs) -> t.Dict[str, t.Any]: +def get_config_json_data_v2(**kwargs: t.Any) -> t.Dict[str, t.Any]: """get_config_json_data_v2""" return { @@ -139,7 +139,7 @@ def get_config_json_data_v2(**kwargs) -> t.Dict[str, t.Any]: } -def get_config_json_data_v3(**kwargs) -> t.Dict[str, t.Any]: +def get_config_json_data_v3(**kwargs: t.Any) -> t.Dict[str, t.Any]: """get_config_json_data_v3""" return { @@ -182,7 +182,7 @@ def get_config_json_data_v3(**kwargs) -> t.Dict[str, t.Any]: } -def get_config_json_data_v4(**kwargs) -> t.Dict[str, t.Any]: +def get_config_json_data_v4(**kwargs: t.Any) -> t.Dict[str, t.Any]: """get_config_json_data_v4""" return { @@ -252,7 +252,7 @@ def test_service_migrate_format( use_mech_marketplace: bool, staking_program_id: str, tmp_path: Path, - ): + ) -> None: """Test services.service.Service.migrate_format()""" config_kwargs = DEFAULT_CONFIG_KWARGS.copy() From 9598ebe0dba7fbf375262046e1d16296c3e8d1de Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Mon, 18 Nov 2024 12:56:06 +0100 Subject: [PATCH 226/463] fix: linters --- operate/operate_types.py | 12 +++++++++++- tests/test_services_service.py | 4 ++-- tox.ini | 10 ++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/operate/operate_types.py b/operate/operate_types.py index 26002611e..9a6838377 100644 --- a/operate/operate_types.py +++ b/operate/operate_types.py @@ -71,7 +71,17 @@ def from_id(cls, chain_id: int) -> "LedgerType": # Dynamically create the Chain enum from the ChainType # TODO: Migrate this to open-autonomy and remove this modified version of Chain here and use the one from open-autonomy # This version of open-autonomy must support the LedgerType to support SOLANA in the future -# If solana support is not fuly implemented, decide to keep this half-baked feature +# If solana support is not fuly implemented, decide to keep this half-baked feature. +# +# TODO: Once the above issue is properly implemented in Open Autonomy, remove the following +# lines from tox.ini: +# +# exclude = ^(operate/operate_types\.py|scripts/setup_wallet\.py|operate/ledger/profiles\.py|operate/ledger/__init__\.py|operate/wallet/master\.py|operate/services/protocol\.py|operate/services/manage\.py|operate/cli\.py)$ +# +# [mypy-operate.*] +# follow_imports = skip # noqa +# +# These lines were itroduced to resolve mypy issues with the temporary Chain/ChainType solution. Chain = enum.Enum( "Chain", [(member.name, member.value) for member in ChainType] diff --git a/tests/test_services_service.py b/tests/test_services_service.py index c2461e755..f040a890e 100644 --- a/tests/test_services_service.py +++ b/tests/test_services_service.py @@ -23,8 +23,8 @@ import typing as t from pathlib import Path -import pytest # type: ignore -from deepdiff import DeepDiff # type: ignore +import pytest +from deepdiff import DeepDiff from operate.services.service import ( SERVICE_CONFIG_PREFIX, diff --git a/tox.ini b/tox.ini index 8d6426723..44a6cb8d7 100644 --- a/tox.ini +++ b/tox.ini @@ -162,6 +162,10 @@ sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER [mypy] strict_optional = True +exclude = ^(operate/operate_types\.py|scripts/setup_wallet\.py|operate/ledger/profiles\.py|operate/ledger/__init__\.py|operate/wallet/master\.py|operate/services/protocol\.py|operate/services/manage\.py|operate/cli\.py)$ + +[mypy-operate.*] +follow_imports = skip [mypy-typing_extentions.*] ignore_missing_imports = True @@ -220,6 +224,12 @@ ignore_missing_imports = True [mypy-eth_utils.*] ignore_missing_imports = True +[mypy-pytest.*] +ignore_missing_imports = True + +[mypy-deepdiff.*] +ignore_missing_imports = True + [testenv:unit-tests] allowlist_externals = poetry commands_pre = From 7536c7cf336ae85f34dca4701ba2d48371a9fb5b Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Mon, 18 Nov 2024 13:21:30 +0100 Subject: [PATCH 227/463] fix: workflow --- .github/workflows/common_checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/common_checks.yml b/.github/workflows/common_checks.yml index a90183604..188c77db2 100644 --- a/.github/workflows/common_checks.yml +++ b/.github/workflows/common_checks.yml @@ -58,7 +58,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest ] - python-version: [ "3.9", "3.10", "3.11" ] + python-version: [ "3.10.9" ] timeout-minutes: 30 From e8e1d6421a81212bb6270a39f681d8f6a932ed5a Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Mon, 18 Nov 2024 17:52:19 +0530 Subject: [PATCH 228/463] Refactor (.env): Remove `DEV_` prefix Signed-off-by: OjusWiZard --- .env.example | 8 ++-- electron/utils/env-validation.js | 12 +++--- frontend/next.config.mjs | 8 ++-- operate/ledger/__init__.py | 38 ++++++++----------- .../tenderly-optimus-fund-eoa-onboarding.js | 12 +++--- .../js/tenderly-optimus-fund-master-safes.js | 16 ++++---- 6 files changed, 43 insertions(+), 51 deletions(-) diff --git a/.env.example b/.env.example index 8719278c7..7556bead9 100644 --- a/.env.example +++ b/.env.example @@ -5,7 +5,7 @@ FORK_URL= DEV_RPC= ## post-refactor pearl envs -GNOSIS_DEV_RPC= -ETHEREUM_DEV_RPC= -OPTIMISM_DEV_RPC= -BASE_DEV_RPC= \ No newline at end of file +GNOSIS_RPC= +ETHEREUM_RPC= +OPTIMISM_RPC= +BASE_RPC= \ No newline at end of file diff --git a/electron/utils/env-validation.js b/electron/utils/env-validation.js index 7c1744ce6..b64d84e87 100644 --- a/electron/utils/env-validation.js +++ b/electron/utils/env-validation.js @@ -16,14 +16,14 @@ const envSchema = z.object({ nodeEnvRegex, 'Invalid NODE_ENV, must be `development` or `production`', ), - BASE_DEV_RPC: z.string().url('Invalid BASE_DEV_RPC must be a valid URL'), - ETHEREUM_DEV_RPC: z + BASE_RPC: z.string().url('Invalid BASE_RPC must be a valid URL'), + ETHEREUM_RPC: z .string() - .url('Invalid ETHEREUM_DEV_RPC_URL must be a valid URL'), - GNOSIS_DEV_RPC: z.string().url('Invalid GNOSIS_DEV_RPC must be a valid URL'), - OPTIMISM_DEV_RPC: z + .url('Invalid ETHEREUM_RPC_URL must be a valid URL'), + GNOSIS_RPC: z.string().url('Invalid GNOSIS_RPC must be a valid URL'), + OPTIMISM_RPC: z .string() - .url('Invalid OPTIMISM_DEV_RPC must be a valid URL'), + .url('Invalid OPTIMISM_RPC must be a valid URL'), }); const validateEnv = () => { diff --git a/frontend/next.config.mjs b/frontend/next.config.mjs index 88a36de2c..e7f80a606 100644 --- a/frontend/next.config.mjs +++ b/frontend/next.config.mjs @@ -32,10 +32,10 @@ const nextConfig = { return config; }, env: { - GNOSIS_RPC: process.env.GNOSIS_DEV_RPC, - OPTIMISM_RPC: process.env.OPTIMISM_DEV_RPC, - BASE_RPC: process.env.BASE_DEV_RPC, - ETHEREUM_RPC: process.env.ETHEREUM_DEV_RPC, + GNOSIS_RPC: process.env.GNOSIS_RPC, + OPTIMISM_RPC: process.env.OPTIMISM_RPC, + BASE_RPC: process.env.BASE_RPC, + ETHEREUM_RPC: process.env.ETHEREUM_RPC, }, }; diff --git a/operate/ledger/__init__.py b/operate/ledger/__init__.py index 76cbf0125..becd45f4f 100644 --- a/operate/ledger/__init__.py +++ b/operate/ledger/__init__.py @@ -28,31 +28,23 @@ from operate.operate_types import Chain, LedgerType -ETHEREUM_PUBLIC_RPC = os.environ.get( - "ETHEREUM_DEV_RPC", "https://ethereum.publicnode.com" -) -GNOSIS_PUBLIC_RPC = os.environ.get( - "GNOSIS_DEV_RPC", "https://gnosis-rpc.publicnode.com" -) +ETHEREUM_PUBLIC_RPC = os.environ.get("ETHEREUM_RPC", "https://ethereum.publicnode.com") +GNOSIS_PUBLIC_RPC = os.environ.get("GNOSIS_RPC", "https://gnosis-rpc.publicnode.com") GOERLI_PUBLIC_RPC = os.environ.get( - "GOERLI_DEV_RPC", "https://ethereum-goerli.publicnode.com" -) -SOLANA_PUBLIC_RPC = os.environ.get( - "SOLANA_DEV_RPC", "https://api.mainnet-beta.solana.com" -) -BASE_PUBLIC_RPC = os.environ.get("BASE_DEV_RPC", "https://mainnet.base.org") -OPTIMISM_PUBLIC_RPC = os.environ.get("OPTIMISM_DEV_RPC", "https://mainnet.optimism.io") -MODE_PUBLIC_RPC = os.environ.get("MODE_DEV_RPC", "https://rpc.mode.network") - -ETHEREUM_RPC = os.environ.get("ETHEREUM_DEV_RPC", "https://ethereum.publicnode.com") -GNOSIS_RPC = os.environ.get( - "GNOSIS_DEV_RPC", "https://rpc-gate.autonolas.tech/gnosis-rpc/" + "GOERLI_RPC", "https://ethereum-goerli.publicnode.com" ) -GOERLI_RPC = os.environ.get("GOERLI_DEV_RPC", "https://ethereum-goerli.publicnode.com") -SOLANA_RPC = os.environ.get("SOLANA_DEV_RPC", "https://api.mainnet-beta.solana.com") -BASE_RPC = os.environ.get("BASE_DEV_RPC", "https://mainnet.base.org") -OPTIMISM_RPC = os.environ.get("OPTIMISM_DEV_RPC", "https://mainnet.optimism.io") -MODE_RPC = os.environ.get("MODE_DEV_RPC", "https://rpc.mode.network") +SOLANA_PUBLIC_RPC = os.environ.get("SOLANA_RPC", "https://api.mainnet-beta.solana.com") +BASE_PUBLIC_RPC = os.environ.get("BASE_RPC", "https://mainnet.base.org") +OPTIMISM_PUBLIC_RPC = os.environ.get("OPTIMISM_RPC", "https://mainnet.optimism.io") +MODE_PUBLIC_RPC = os.environ.get("MODE_RPC", "https://rpc.mode.network") + +ETHEREUM_RPC = os.environ.get("ETHEREUM_RPC", "https://ethereum.publicnode.com") +GNOSIS_RPC = os.environ.get("GNOSIS_RPC", "https://rpc-gate.autonolas.tech/gnosis-rpc/") +GOERLI_RPC = os.environ.get("GOERLI_RPC", "https://ethereum-goerli.publicnode.com") +SOLANA_RPC = os.environ.get("SOLANA_RPC", "https://api.mainnet-beta.solana.com") +BASE_RPC = os.environ.get("BASE_RPC", "https://mainnet.base.org") +OPTIMISM_RPC = os.environ.get("OPTIMISM_RPC", "https://mainnet.optimism.io") +MODE_RPC = os.environ.get("MODE_RPC", "https://rpc.mode.network") PUBLIC_RPCS = { Chain.ETHEREUM: ETHEREUM_PUBLIC_RPC, diff --git a/scripts/js/tenderly-optimus-fund-eoa-onboarding.js b/scripts/js/tenderly-optimus-fund-eoa-onboarding.js index 0a58942c1..9f551c801 100644 --- a/scripts/js/tenderly-optimus-fund-eoa-onboarding.js +++ b/scripts/js/tenderly-optimus-fund-eoa-onboarding.js @@ -25,17 +25,17 @@ const setBalance = async (masterEoa, rpc) => fetch(rpc, { }), }).then(() => console.log(`Successfully set balance for ${masterEoa} on ${rpc}`)) -const main = async () => { +const main = async () => { const rpcs = { - gnosis: process.env.GNOSIS_DEV_RPC, - optimus: process.env.OPTIMISM_DEV_RPC, - base: process.env.BASE_DEV_RPC, - ethereum: process.env.ETHEREUM_DEV_RPC + gnosis: process.env.GNOSIS_RPC, + optimus: process.env.OPTIMISM_RPC, + base: process.env.BASE_RPC, + ethereum: process.env.ETHEREUM_RPC }; console.log(rpcs) - await Promise.all(Object.values(rpcs).map(rpc => setBalance(masterEoa, rpc))); + await Promise.all(Object.values(rpcs).map(rpc => setBalance(masterEoa, rpc))); } main() \ No newline at end of file diff --git a/scripts/js/tenderly-optimus-fund-master-safes.js b/scripts/js/tenderly-optimus-fund-master-safes.js index b17215026..626e0280e 100644 --- a/scripts/js/tenderly-optimus-fund-master-safes.js +++ b/scripts/js/tenderly-optimus-fund-master-safes.js @@ -42,22 +42,22 @@ const setErc20Balance = async (erc20Address, masterSafeAddress, rpc) => fetch(rp }), }).then(() => console.log(`Successfully set ERC20 balance for ${masterSafeAddress} on ${rpc}`)) -const main = async () => { +const main = async () => { const rpcs = { - gnosis: process.env.GNOSIS_DEV_RPC, - optimism: process.env.OPTIMISM_DEV_RPC, - base: process.env.BASE_DEV_RPC, - ethereum: process.env.ETHEREUM_DEV_RPC + gnosis: process.env.GNOSIS_RPC, + optimism: process.env.OPTIMISM_RPC, + base: process.env.BASE_RPC, + ethereum: process.env.ETHEREUM_RPC }; const erc20Addresses = { olas: { gnosis: "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", optimism: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527", - ethereum: + ethereum: "0x0001A500A6B18995B03f44bb040A5fFc28E45CB0", base: - "0x4B1a99467a284CC690e3237bc69105956816F762" + "0x4B1a99467a284CC690e3237bc69105956816F762" }, usdc: { ethereum: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" @@ -65,7 +65,7 @@ const main = async () => { } // ETH on all - await Promise.all(Object.values(rpcs).map(rpc => setBalance(masterSafeAddress, rpc))); + await Promise.all(Object.values(rpcs).map(rpc => setBalance(masterSafeAddress, rpc))); // ERC20s await setErc20Balance(erc20Addresses.usdc.ethereum, masterSafeAddress, rpcs.ethereum) From b0577b7c39c8c31a150749cc48a8cce5e9de99c9 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Mon, 18 Nov 2024 13:28:09 +0100 Subject: [PATCH 229/463] fix: workflow --- .github/workflows/common_checks.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/common_checks.yml b/.github/workflows/common_checks.yml index 188c77db2..f1bf4b9d5 100644 --- a/.github/workflows/common_checks.yml +++ b/.github/workflows/common_checks.yml @@ -69,4 +69,6 @@ jobs: python-version: ${{ matrix.python-version }} - name: Run unit tests - run: tox -e unit-tests + run: | + pip install tomte[tox]==0.2.15 + tox -e unit-tests From ef7c7b173075e8263d4ef3f0f6025b029430579d Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Mon, 18 Nov 2024 13:41:19 +0100 Subject: [PATCH 230/463] fix: linters --- pytest.ini | 5 +++++ tox.ini | 7 +++---- 2 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 pytest.ini diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 000000000..f5276a231 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +log_cli = 1 +log_cli_level = INFO +log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s) +log_cli_date_format=%Y-%m-%d %H:%M:%S diff --git a/tox.ini b/tox.ini index 44a6cb8d7..e59dbb791 100644 --- a/tox.ini +++ b/tox.ini @@ -231,8 +231,7 @@ ignore_missing_imports = True ignore_missing_imports = True [testenv:unit-tests] -allowlist_externals = poetry -commands_pre = - poetry install +deps = + pytest==7.2.1 commands = - poetry run pytest tests/ \ No newline at end of file + pytest tests/ \ No newline at end of file From ab17df66613315dcf9a25a9f6e6fe4a89e451c4b Mon Sep 17 00:00:00 2001 From: Mohan Date: Mon, 18 Nov 2024 18:16:49 +0530 Subject: [PATCH 231/463] feat: Refactor StakingProgram context and program (#454) * fix: correct comment formatting in StakingProgramProvider * refactor: update StakingProgramProvider to use react-query for fetching active staking program * refactor: enhance useStakingRewardsDetails and useAvailableRewardsForEpoch to utilize default staking program ID * feat: add staking program key to react-query keys for improved data fetching * refactor: simplify ServicesProvider and useStakingProgram by removing unused variables and updating default staking program ID * refactor: should not update default staking contract * refactor: rename StakingContractInfoProvider to StakingContractDetailsProvider for clarity * feat: add query key for staking contract details by staking program and implement related hook in StakingContractDetailsProvider * feat: add hook to fetch all staking contract details and update context provider * refactor: rename StakingContractInfo to StakingContractDetails and update related references * refactor: update query keys for staking contract details to improve clarity and consistency * refactor: rename isAllStakingContractDetailsListLoaded to isAllStakingContractDetailsRecordLoaded for consistency * refactor: rename useStakingContractInfo to useStakingContractDetails for consistency * feat: add utility types for nullable and optional values * refactor: simplify staking contract hooks and improve dynamic agent and chain selection * refactor: update react-query keys for staking program and improve type handling * refactor: rename staking contract detail fetching methods for clarity and consistency * refactor: update serviceConfigId type in react-query keys and adjust related queries * fix: correct enabled condition in useStakingContractDetails hook to include chainId --- .../header/AgentButton/AgentButton.tsx | 4 +- .../AgentButton/AgentNotRunningButton.tsx | 22 +-- .../header/CannotStartAgentPopover.tsx | 16 +- frontend/components/MainPage/index.tsx | 11 +- .../NoAvailableSlotsOnTheContract.tsx | 15 +- .../sections/StakingContractUpdate.tsx | 11 +- .../CantMigrateAlert.tsx | 7 +- .../CountdownUntilMigration.tsx | 4 +- .../StakingContractSection/MigrateButton.tsx | 23 +-- .../StakingContractDetails.tsx | 24 +-- .../StakingContractSection/useMigrate.tsx | 25 +-- frontend/constants/react-query-keys.ts | 19 +++ frontend/context/RewardProvider.tsx | 24 +-- frontend/context/ServicesProvider.tsx | 20 +-- .../StakingContractDetailsProvider.tsx | 143 +++++++++++++++++ .../context/StakingContractInfoProvider.tsx | 148 ------------------ frontend/context/StakingProgramProvider.tsx | 106 +++++++------ frontend/hooks/useAgent.ts | 3 + frontend/hooks/useChainId.ts | 3 + frontend/hooks/useNotifyOnNewEpoch.ts | 10 +- frontend/hooks/useService.ts | 15 ++ ...ctInfo.ts => useStakingContractDetails.ts} | 87 +++++++--- frontend/hooks/useStakingProgram.ts | 9 +- frontend/pages/_app.tsx | 6 +- frontend/service/agents/PredictTrader.ts | 10 +- frontend/types/Autonolas.ts | 2 +- frontend/types/Util.ts | 5 + 27 files changed, 437 insertions(+), 335 deletions(-) create mode 100644 frontend/context/StakingContractDetailsProvider.tsx delete mode 100644 frontend/context/StakingContractInfoProvider.tsx create mode 100644 frontend/hooks/useAgent.ts create mode 100644 frontend/hooks/useChainId.ts rename frontend/hooks/{useStakingContractInfo.ts => useStakingContractDetails.ts} (55%) create mode 100644 frontend/types/Util.ts diff --git a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx index d5cf98f2d..c133e227a 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx @@ -4,7 +4,7 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; -import { useStakingContractInfo } from '@/hooks/useStakingContractInfo'; +import { useStakingContractDetails } from '@/hooks/useStakingContractDetails'; import { CannotStartAgentDueToUnexpectedError, @@ -22,7 +22,7 @@ export const AgentButton = () => { deploymentStatus: serviceStatus, isLoaded, } = useService({ serviceConfigId: selectedService?.service_config_id }); - const { isEligibleForStaking, isAgentEvicted } = useStakingContractInfo(); + const { isEligibleForStaking, isAgentEvicted } = useStakingContractDetails(); return useMemo(() => { if (!isLoaded) { diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index 962bae7ce..01a749a9e 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -14,8 +14,8 @@ import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useActiveStakingContractInfo, useStakingContractContext, - useStakingContractInfo, -} from '@/hooks/useStakingContractInfo'; + useStakingContractDetails, +} from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { useStore } from '@/hooks/useStore'; import { useWallet } from '@/hooks/useWallet'; @@ -52,9 +52,9 @@ export const AgentNotRunningButton = () => { const { storeState } = useStore(); const { - isStakingContractInfoRecordLoaded, + isAllStakingContractDetailsRecordLoaded, setIsPaused: setIsStakingContractInfoPollingPaused, - updateActiveStakingContractInfo, + refetchActiveStakingContractDetails, } = useStakingContractContext(); const { activeStakingProgramId, defaultStakingProgramId } = @@ -63,12 +63,12 @@ export const AgentNotRunningButton = () => { const { isEligibleForStaking, isAgentEvicted, isServiceStaked } = useActiveStakingContractInfo(); - const { hasEnoughServiceSlots } = useStakingContractInfo( + const { hasEnoughServiceSlots } = useStakingContractDetails( activeStakingProgramId ?? defaultStakingProgramId, ); // const minStakingDeposit = - // stakingContractInfoRecord?.[activeStakingProgram ?? defaultStakingProgram] + // allStakingContractDetailsRecord?.[activeStakingProgram ?? defaultStakingProgram] // ?.minStakingDeposit; const requiredOlas = @@ -153,10 +153,10 @@ export const AgentNotRunningButton = () => { await delayInSeconds(5); // update provider states sequentially - // service id is required before activeStakingContractInfo & balances can be updated + // service id is required before activeStakingContractDetails & balances can be updated try { await updateServicesState?.(); // reload the available services - await updateActiveStakingContractInfo(); // reload active staking contract with new service + await refetchActiveStakingContractDetails(); // reload active staking contract with new service await updateBalances(); // reload the balances } catch (error) { console.error(error); @@ -177,12 +177,12 @@ export const AgentNotRunningButton = () => { activeStakingProgramId, serviceTemplate, updateServicesState, - updateActiveStakingContractInfo, + refetchActiveStakingContractDetails, updateBalances, ]); const isDeployable = useMemo(() => { - if (!isStakingContractInfoRecordLoaded) return false; + if (!isAllStakingContractDetailsRecordLoaded) return false; // if the agent is NOT running and the balance is too low, // user should not be able to start the agent @@ -217,7 +217,7 @@ export const AgentNotRunningButton = () => { return hasEnoughOlas && hasEnoughEth; }, [ - isStakingContractInfoRecordLoaded, + isAllStakingContractDetailsRecordLoaded, deploymentStatus, isLowBalance, requiredOlas, diff --git a/frontend/components/MainPage/header/CannotStartAgentPopover.tsx b/frontend/components/MainPage/header/CannotStartAgentPopover.tsx index 619abdfcd..5aa8d37e1 100644 --- a/frontend/components/MainPage/header/CannotStartAgentPopover.tsx +++ b/frontend/components/MainPage/header/CannotStartAgentPopover.tsx @@ -7,8 +7,8 @@ import { SUPPORT_URL } from '@/constants/urls'; import { useActiveStakingContractInfo, useStakingContractContext, - useStakingContractInfo, -} from '@/hooks/useStakingContractInfo'; + useStakingContractDetails, +} from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { formatToShortDateTime } from '@/utils/time'; @@ -50,11 +50,12 @@ export const CannotStartAgentDueToUnexpectedError = () => ( const evictedDescription = "You didn't run your agent enough and it missed its targets multiple times. You can run the agent again when the eviction period ends."; const AgentEvictedPopover = () => { - const { isStakingContractInfoRecordLoaded } = useStakingContractContext(); + const { isAllStakingContractDetailsRecordLoaded } = + useStakingContractContext(); const { evictionExpiresAt } = useActiveStakingContractInfo(); - if (!isStakingContractInfoRecordLoaded) return null; + if (!isAllStakingContractDetailsRecordLoaded) return null; return ( ( ); export const CannotStartAgentPopover = () => { - const { isStakingContractInfoRecordLoaded } = useStakingContractContext(); + const { isAllStakingContractDetailsRecordLoaded } = + useStakingContractContext(); const { activeStakingProgramId, defaultStakingProgramId } = useStakingProgram(); @@ -126,11 +128,11 @@ export const CannotStartAgentPopover = () => { const { isAgentEvicted, isEligibleForStaking } = useActiveStakingContractInfo(); - const { hasEnoughServiceSlots, isRewardsAvailable } = useStakingContractInfo( + const { hasEnoughServiceSlots, isRewardsAvailable } = useStakingContractDetails( activeStakingProgramId ?? defaultStakingProgramId, ); - if (!isStakingContractInfoRecordLoaded) return null; + if (!isAllStakingContractDetailsRecordLoaded) return null; if (isEligibleForStaking) return null; if (!hasEnoughServiceSlots) return ; if (!isRewardsAvailable) return ; diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index 7ad23a6ed..f078e7679 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -10,8 +10,8 @@ import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; import { useStakingContractContext, - useStakingContractInfo, -} from '@/hooks/useStakingContractInfo'; + useStakingContractDetails, +} from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; // import { useStakingProgram } from '@/hooks/useStakingProgram'; @@ -37,9 +37,10 @@ export const Main = () => { const { activeStakingProgramId, defaultStakingProgramId } = useStakingProgram(); - const { isStakingContractInfoRecordLoaded } = useStakingContractContext(); + const { isAllStakingContractDetailsRecordLoaded } = + useStakingContractContext(); - const { hasEnoughServiceSlots } = useStakingContractInfo( + const { hasEnoughServiceSlots } = useStakingContractDetails( activeStakingProgramId ?? defaultStakingProgramId, ); @@ -61,7 +62,7 @@ export const Main = () => { const hideMainOlasBalanceTopBorder = [ !backupSafeAddress, activeStakingProgramId === StakingProgramId.Alpha, - isStakingContractInfoRecordLoaded && !hasEnoughServiceSlots, + isAllStakingContractDetailsRecordLoaded && !hasEnoughServiceSlots, ].some((condition) => !!condition); return ( diff --git a/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx b/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx index 9542311bd..f7de19c59 100644 --- a/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx +++ b/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx @@ -6,8 +6,8 @@ import { usePageState } from '@/hooks/usePageState'; import { useActiveStakingContractInfo, useStakingContractContext, - useStakingContractInfo, -} from '@/hooks/useStakingContractInfo'; + useStakingContractDetails, +} from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { CustomAlert } from '../../../Alert'; @@ -24,14 +24,15 @@ export const NoAvailableSlotsOnTheContract = () => { defaultStakingProgramMeta, } = useStakingProgram(); - const { isStakingContractInfoRecordLoaded } = useStakingContractContext(); + const { isAllStakingContractDetailsRecordLoaded } = + useStakingContractContext(); const { isServiceStaked } = useActiveStakingContractInfo(); - const { hasEnoughServiceSlots } = useStakingContractInfo( + const { hasEnoughServiceSlots } = useStakingContractDetails( activeStakingProgramId ?? defaultStakingProgramId, ); const stakingProgramName = useMemo(() => { - if (!isStakingContractInfoRecordLoaded) return null; + if (!isAllStakingContractDetailsRecordLoaded) return null; if (activeStakingProgramId) { return activeStakingProgramMeta?.name; } @@ -40,10 +41,10 @@ export const NoAvailableSlotsOnTheContract = () => { activeStakingProgramId, activeStakingProgramMeta?.name, defaultStakingProgramMeta?.name, - isStakingContractInfoRecordLoaded, + isAllStakingContractDetailsRecordLoaded, ]); - if (!isStakingContractInfoRecordLoaded) return null; + if (!isAllStakingContractDetailsRecordLoaded) return null; if (hasEnoughServiceSlots) return null; if (isServiceStaked) return null; diff --git a/frontend/components/MainPage/sections/StakingContractUpdate.tsx b/frontend/components/MainPage/sections/StakingContractUpdate.tsx index 3406574e8..a9d90532e 100644 --- a/frontend/components/MainPage/sections/StakingContractUpdate.tsx +++ b/frontend/components/MainPage/sections/StakingContractUpdate.tsx @@ -7,7 +7,7 @@ import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { Pages } from '@/enums/PageState'; import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; -import { useStakingContractContext } from '@/hooks/useStakingContractInfo'; +import { useStakingContractContext } from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { CardSection } from '../../styled/CardSection'; @@ -22,7 +22,8 @@ export const StakingContractUpdate = () => { defaultStakingProgramId, } = useStakingProgram(); - const { isStakingContractInfoRecordLoaded } = useStakingContractContext(); + const { isAllStakingContractDetailsRecordLoaded } = + useStakingContractContext(); const { serviceStatus } = useServices(); const serviceIsTransitioning = useMemo( @@ -44,7 +45,9 @@ export const StakingContractUpdate = () => { type="link" className="p-0" onClick={() => goto(Pages.ManageStaking)} - disabled={!isStakingContractInfoRecordLoaded || serviceIsTransitioning} + disabled={ + !isAllStakingContractDetailsRecordLoaded || serviceIsTransitioning + } > {stakingContractName} @@ -53,7 +56,7 @@ export const StakingContractUpdate = () => { }, [ goto, isActiveStakingProgramLoaded, - isStakingContractInfoRecordLoaded, + isAllStakingContractDetailsRecordLoaded, serviceIsTransitioning, stakingContractName, ]); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx index 6bfb349da..a045fc851 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx @@ -10,7 +10,7 @@ import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useActiveStakingContractInfo, useStakingContractContext, -} from '@/hooks/useStakingContractInfo'; +} from '@/hooks/useStakingContractDetails'; import { getMinimumStakedAmountRequired } from '@/utils/service'; import { CantMigrateReason } from './useMigrate'; @@ -23,7 +23,8 @@ const AlertInsufficientMigrationFunds = ({ stakingProgramId, }: CantMigrateAlertProps) => { const { serviceTemplate } = useServiceTemplates(); - const { isStakingContractInfoRecordLoaded } = useStakingContractContext(); + const { isAllStakingContractDetailsRecordLoaded } = + useStakingContractContext(); const { isServiceStaked } = useActiveStakingContractInfo(); const { masterSafeBalance: safeBalance, totalOlasStakedBalance } = useBalance(); @@ -34,7 +35,7 @@ const AlertInsufficientMigrationFunds = ({ stakingProgramId, ); - if (!isStakingContractInfoRecordLoaded) return null; + if (!isAllStakingContractDetailsRecordLoaded) return null; if (isNil(totalOlasRequiredForStaking)) return null; if (isNil(safeBalance?.OLAS)) return null; if (isNil(totalOlasStakedBalance)) return null; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CountdownUntilMigration.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CountdownUntilMigration.tsx index 68d1c71b0..eb4b9a39d 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CountdownUntilMigration.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CountdownUntilMigration.tsx @@ -4,14 +4,14 @@ import { useState } from 'react'; import { useInterval } from 'usehooks-ts'; import { POPOVER_WIDTH_LARGE } from '@/constants/width'; -import { StakingContractInfo } from '@/types/Autonolas'; +import { StakingContractDetails } from '@/types/Autonolas'; const { Text } = Typography; export const CountdownUntilMigration = ({ currentStakingContractInfo, }: { - currentStakingContractInfo: Partial; + currentStakingContractInfo: Partial; }) => { const [secondsUntilReady, setSecondsUntilMigration] = useState(); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index d42465e91..bb63f7acc 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -13,9 +13,8 @@ import { useServices } from '@/hooks/useServices'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useActiveStakingContractInfo, - useStakingContractInfo, -} from '@/hooks/useStakingContractInfo'; -import { useStakingProgram } from '@/hooks/useStakingProgram'; + useStakingContractDetails, +} from '@/hooks/useStakingContractDetails'; import { ServicesService } from '@/service/Services'; import { CountdownUntilMigration } from './CountdownUntilMigration'; @@ -43,21 +42,20 @@ export const MigrateButton = ({ }); const { setIsPaused: setIsBalancePollingPaused } = useBalance(); - const { updateActiveStakingProgramId } = useStakingProgram(); - const { activeStakingContractInfo, isActiveStakingContractInfoLoaded } = + const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded } = useActiveStakingContractInfo(); const { stakingContractInfo: defaultStakingContractInfo } = - useStakingContractInfo(defaultStakingProgramId); + useStakingContractDetails(defaultStakingProgramId); const currentStakingContractInfo = useMemo(() => { - if (!isActiveStakingContractInfoLoaded) return; - if (activeStakingContractInfo) return activeStakingContractInfo; + if (!isActiveStakingContractDetailsLoaded) return; + if (activeStakingContractDetails) return activeStakingContractDetails; return defaultStakingContractInfo; }, [ - activeStakingContractInfo, + activeStakingContractDetails, defaultStakingContractInfo, - isActiveStakingContractInfoLoaded, + isActiveStakingContractDetailsLoaded, ]); const { setMigrationModalOpen } = useModals(); @@ -102,7 +100,10 @@ export const MigrateButton = ({ onClick={async () => { setIsServicePollingPaused(true); setIsBalancePollingPaused(true); - setDefaultStakingProgramId(stakingProgramId); + + // TODO: we should not get the default staking program id + // from the context, we should get it from the service + // setDefaultStakingProgramId(stakingProgramId); try { setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYING); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/StakingContractDetails.tsx b/frontend/components/ManageStakingPage/StakingContractSection/StakingContractDetails.tsx index fbb26ad6a..17506754e 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/StakingContractDetails.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/StakingContractDetails.tsx @@ -3,23 +3,25 @@ import { useMemo } from 'react'; import { InfoBreakdownList } from '@/components/InfoBreakdown'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useStakingContractContext } from '@/hooks/useStakingContractInfo'; +import { useStakingContractContext } from '@/hooks/useStakingContractDetails'; export const StakingContractDetails = ({ stakingProgramId, }: { stakingProgramId: StakingProgramId; }) => { - const { stakingContractInfoRecord, isStakingContractInfoRecordLoaded } = - useStakingContractContext(); + const { + allStakingContractDetailsRecord, + isAllStakingContractDetailsRecordLoaded, + } = useStakingContractContext(); const list = useMemo(() => { - if (!isStakingContractInfoRecordLoaded) return; - if (!stakingContractInfoRecord) return; + if (!isAllStakingContractDetailsRecordLoaded) return; + if (!allStakingContractDetailsRecord) return; if (!stakingProgramId) return; - if (!stakingContractInfoRecord?.[stakingProgramId]) return; + if (!allStakingContractDetailsRecord?.[stakingProgramId]) return; - const details = stakingContractInfoRecord[stakingProgramId]; + const details = allStakingContractDetailsRecord[stakingProgramId]; return [ { @@ -41,16 +43,16 @@ export const StakingContractDetails = ({ }, ]; }, [ - isStakingContractInfoRecordLoaded, - stakingContractInfoRecord, + isAllStakingContractDetailsRecordLoaded, + allStakingContractDetailsRecord, stakingProgramId, ]); - if (!isStakingContractInfoRecordLoaded) { + if (!isAllStakingContractDetailsRecordLoaded) { return ; } - if (!stakingContractInfoRecord) { + if (!allStakingContractDetailsRecord) { return ( { useStakingProgram(); const { needsInitialFunding } = useNeedsFunds(); - const { stakingContractInfoRecord, isStakingContractInfoRecordLoaded } = - useStakingContractContext(); + const { + allStakingContractDetailsRecord, + isAllStakingContractDetailsRecordLoaded, + } = useStakingContractContext(); const { isServiceStaked, isServiceStakedForMinimumDuration } = useActiveStakingContractInfo(); const { stakingContractInfo, hasEnoughServiceSlots } = - useStakingContractInfo(stakingProgramId); + useStakingContractDetails(stakingProgramId); const { isFetched: isServicesLoaded } = useServices(); @@ -116,7 +118,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { return { canMigrate: false, reason: CantMigrateReason.LoadingBalance }; } - if (!isStakingContractInfoRecordLoaded) { + if (!isAllStakingContractDetailsRecordLoaded) { return { canMigrate: false, reason: CantMigrateReason.LoadingStakingContractInfo, @@ -196,7 +198,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { }, [ isServicesLoaded, isBalanceLoaded, - isStakingContractInfoRecordLoaded, + isAllStakingContractDetailsRecordLoaded, stakingContractInfo, activeStakingProgramId, stakingProgramId, @@ -236,14 +238,15 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { // staking contract requirements - if (!isStakingContractInfoRecordLoaded) { + if (!isAllStakingContractDetailsRecordLoaded) { return { canMigrate: false, reason: CantMigrateReason.LoadingStakingContractInfo, }; } - const stakingContractInfo = stakingContractInfoRecord?.[stakingProgramId]; + const stakingContractInfo = + allStakingContractDetailsRecord?.[stakingProgramId]; if (!stakingContractInfo) { return { @@ -295,8 +298,8 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { isServicesLoaded, isBalanceLoaded, hasEnoughEthForInitialFunding, - isStakingContractInfoRecordLoaded, - stakingContractInfoRecord, + isAllStakingContractDetailsRecordLoaded, + allStakingContractDetailsRecord, stakingProgramId, hasEnoughOlasForFirstRun, serviceStatus, diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index 4cf542fb9..89279af23 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -3,8 +3,27 @@ export const REACT_QUERY_KEYS = { SERVICES_KEY: ['services'] as const, SERVICE_DEPLOYMENT_STATUS_KEY: (serviceConfigId: string) => ['serviceStatus', serviceConfigId] as const, + + // staking programs + STAKING_CONTRACT_DETAILS_BY_STAKING_PROGRAM_KEY: ( + chainId: number, + serviceConfigId: number, + activeStakingProgramId: string, + ) => + [ + 'stakingContractDetailsByStakingProgramId', + chainId, + serviceConfigId, + activeStakingProgramId, + ] as const, + ALL_STAKING_CONTRACT_DETAILS: (chainId: number, stakingProgramId: string) => + ['allStakingContractDetails', chainId, stakingProgramId] as const, + STAKING_PROGRAM_KEY: (chainId: number, serviceConfigId: number) => + ['stakingProgram', chainId, serviceConfigId] as const, + // wallets WALLETS_KEY: ['wallets'] as const, + // rewards REWARDS_KEY: ( chainId: number, diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index d3327ddd7..192b82a87 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -48,9 +48,12 @@ const currentChainId = GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with dynami */ const useStakingRewardsDetails = () => { const { isOnline } = useContext(OnlineStatusContext); - const { activeStakingProgramId } = useContext(StakingProgramContext); + const { activeStakingProgramId, defaultStakingProgramId } = useContext( + StakingProgramContext, + ); + const stakingProgramId = activeStakingProgramId ?? defaultStakingProgramId; - const { selectedService, isLoaded } = useServices(); + const { selectedService, isFetched: isLoaded } = useServices(); const serviceConfigId = isLoaded && selectedService ? selectedService?.service_config_id : ''; const { service } = useService({ serviceConfigId }); @@ -64,7 +67,7 @@ const useStakingRewardsDetails = () => { queryKey: REACT_QUERY_KEYS.REWARDS_KEY( currentChainId, serviceConfigId, - activeStakingProgramId!, + stakingProgramId!, multisig!, token!, ), @@ -73,13 +76,13 @@ const useStakingRewardsDetails = () => { { agentMultisigAddress: multisig!, serviceId: token!, - stakingProgramId: activeStakingProgramId!, + stakingProgramId: stakingProgramId!, chainId: currentChainId, }, ); return StakingRewardsInfoSchema.parse(response); }, - enabled: !!isOnline && !!activeStakingProgramId && !!multisig && !!token, + enabled: !!isOnline && !!stakingProgramId && !!multisig && !!token, refetchInterval: isOnline ? FIVE_SECONDS_INTERVAL : false, refetchOnWindowFocus: false, }); @@ -93,7 +96,9 @@ const useAvailableRewardsForEpoch = () => { const { activeStakingProgramId, defaultStakingProgramId } = useContext( StakingProgramContext, ); - const { selectedService, isLoaded } = useServices(); + const stakingProgramId = activeStakingProgramId ?? defaultStakingProgramId; + + const { selectedService, isFetched: isLoaded } = useServices(); const serviceConfigId = isLoaded && selectedService ? selectedService?.service_config_id : ''; @@ -101,17 +106,16 @@ const useAvailableRewardsForEpoch = () => { queryKey: REACT_QUERY_KEYS.AVAILABLE_REWARDS_FOR_EPOCH_KEY( currentChainId, serviceConfigId, - activeStakingProgramId!, + stakingProgramId!, currentChainId, ), queryFn: async () => { return await currentAgent.serviceApi.getAvailableRewardsForEpoch( - activeStakingProgramId ?? defaultStakingProgramId, + stakingProgramId, currentChainId, ); }, - enabled: - !!isOnline && !!activeStakingProgramId && !!defaultStakingProgramId, + enabled: !!isOnline && !!stakingProgramId, refetchInterval: isOnline ? FIVE_SECONDS_INTERVAL : false, refetchOnWindowFocus: false, }); diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index d0ff72dc2..2a79934ec 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -14,12 +14,7 @@ import { MiddlewareServiceResponse } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { ChainId } from '@/enums/Chain'; -import { - AgentEoa, - AgentWallets, - WalletOwner, - WalletType, -} from '@/enums/Wallet'; +import { AgentWallets, WalletOwner, WalletType } from '@/enums/Wallet'; import { UsePause, usePause } from '@/hooks/usePause'; import { ServicesService } from '@/service/Services'; import { Service } from '@/types/Service'; @@ -116,14 +111,11 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { if (instances) { acc.push( - ...instances.map( - (instance: string) => - ({ - address: instance, - type: WalletType.EOA, - owner: WalletOwner.Agent, - }), - ), + ...instances.map((instance: string) => ({ + address: instance, + type: WalletType.EOA, + owner: WalletOwner.Agent, + })), ); } diff --git a/frontend/context/StakingContractDetailsProvider.tsx b/frontend/context/StakingContractDetailsProvider.tsx new file mode 100644 index 000000000..8796e5daf --- /dev/null +++ b/frontend/context/StakingContractDetailsProvider.tsx @@ -0,0 +1,143 @@ +import { useQueries } from '@tanstack/react-query'; +import { + createContext, + Dispatch, + PropsWithChildren, + SetStateAction, + useCallback, + useContext, + useState, +} from 'react'; + +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { StakingProgramId } from '@/enums/StakingProgram'; +import { useAgent } from '@/hooks/useAgent'; +import { useChainId } from '@/hooks/useChainId'; +import { useStakingContractDetailsByStakingProgram } from '@/hooks/useStakingContractDetails'; +import { StakingContractDetails } from '@/types/Autonolas'; + +import { + INITIAL_DEFAULT_STAKING_PROGRAM_ID, + StakingProgramContext, +} from './StakingProgramProvider'; + +/** + * hook to get all staking contract details + */ +const useAllStakingContractDetails = () => { + const stakingPrograms = [INITIAL_DEFAULT_STAKING_PROGRAM_ID]; + const chainId = useChainId(); + const currentAgent = useAgent(); + + const queryResults = useQueries({ + queries: stakingPrograms.map((programId) => ({ + queryKey: REACT_QUERY_KEYS.ALL_STAKING_CONTRACT_DETAILS( + chainId, + programId, + ), + queryFn: async () => + await currentAgent.serviceApi.getStakingContractDetailsByName( + programId, + chainId, + ), + onError: (error: Error) => { + console.error( + `Error fetching staking details for ${programId}:`, + error, + ); + }, + })), + }); + + // Aggregate results into a record + const allStakingContractDetailsRecord = stakingPrograms.reduce( + (record, programId, index) => { + const query = queryResults[index]; + if (query.status === 'success') { + record[programId] = query.data; + } else if (query.status === 'error') { + console.error(query.error); + } + return record; + }, + {} as Record>, + ); + + const isAllStakingContractDetailsLoaded = queryResults.every( + (query) => query.isSuccess, + ); + + return { allStakingContractDetailsRecord, isAllStakingContractDetailsLoaded }; +}; + +type StakingContractDetailsContextProps = { + activeStakingContractDetails?: Partial; + isActiveStakingContractDetailsLoaded: boolean; + isPaused: boolean; + allStakingContractDetailsRecord?: Record< + StakingProgramId, + Partial + >; + isAllStakingContractDetailsRecordLoaded: boolean; + refetchActiveStakingContractDetails: () => Promise; + setIsPaused: Dispatch>; +}; + +/** + * Context for staking contract details + */ +export const StakingContractDetailsContext = + createContext({ + activeStakingContractDetails: undefined, + isPaused: false, + isAllStakingContractDetailsRecordLoaded: false, + isActiveStakingContractDetailsLoaded: false, + allStakingContractDetailsRecord: undefined, + refetchActiveStakingContractDetails: async () => {}, + setIsPaused: () => {}, + }); + +/** + * Provider for staking contract details + */ +export const StakingContractDetailsProvider = ({ + children, +}: PropsWithChildren) => { + const [isPaused, setIsPaused] = useState(false); + + const { activeStakingProgramId } = useContext(StakingProgramContext); + const { + data: activeStakingContractDetails, + isLoading: isActiveStakingContractDetailsLoading, + refetch: refetchActiveStakingContract, + } = useStakingContractDetailsByStakingProgram( + activeStakingProgramId, + isPaused, + ); + + const { allStakingContractDetailsRecord, isAllStakingContractDetailsLoaded } = + useAllStakingContractDetails(); + + const refetchActiveStakingContractDetails = useCallback(async () => { + await refetchActiveStakingContract(); + }, [refetchActiveStakingContract]); + + return ( + + {children} + + ); +}; diff --git a/frontend/context/StakingContractInfoProvider.tsx b/frontend/context/StakingContractInfoProvider.tsx deleted file mode 100644 index e023be78e..000000000 --- a/frontend/context/StakingContractInfoProvider.tsx +++ /dev/null @@ -1,148 +0,0 @@ -import { - createContext, - Dispatch, - PropsWithChildren, - SetStateAction, - useCallback, - useContext, - useEffect, - useMemo, - useState, -} from 'react'; -import { useInterval } from 'usehooks-ts'; - -import { CHAIN_CONFIG } from '@/config/chains'; -import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; -import { StakingProgramId } from '@/enums/StakingProgram'; -import { AutonolasService } from '@/service/Autonolas'; -import { StakingContractInfo } from '@/types/Autonolas'; - -import { ServicesContext } from './ServicesProvider'; -import { - DEFAULT_STAKING_PROGRAM_ID, - StakingProgramContext, -} from './StakingProgramProvider'; - -type StakingContractInfoContextProps = { - activeStakingContractInfo?: Partial; - isActiveStakingContractInfoLoaded: boolean; - isPaused: boolean; - stakingContractInfoRecord?: Record< - StakingProgramId, - Partial - >; - isStakingContractInfoRecordLoaded: boolean; - updateActiveStakingContractInfo: () => Promise; - setIsPaused: Dispatch>; -}; - -export const StakingContractInfoContext = - createContext({ - activeStakingContractInfo: undefined, - isPaused: false, - isStakingContractInfoRecordLoaded: false, - isActiveStakingContractInfoLoaded: false, - stakingContractInfoRecord: undefined, - updateActiveStakingContractInfo: async () => {}, - setIsPaused: () => {}, - }); - -export const StakingContractInfoProvider = ({ - children, -}: PropsWithChildren) => { - const { services } = useContext(ServicesContext); - const { activeStakingProgramId } = useContext(StakingProgramContext); - - const [isPaused, setIsPaused] = useState(false); - const [ - isStakingContractInfoRecordLoaded, - setIsStakingContractInfoRecordLoaded, - ] = useState(false); - const [ - isActiveStakingContractInfoLoaded, - setIsActiveStakingContractInfoLoaded, - ] = useState(false); - - const [activeStakingContractInfo, setActiveStakingContractInfo] = - useState>(); - - const [stakingContractInfoRecord, setStakingContractInfoRecord] = - useState>>(); - - const serviceId = useMemo( - () => - services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.token, - [services], - ); - - /** Updates staking contract info specific to the actively staked service owned by the user */ - const updateActiveStakingContractInfo = useCallback(async () => { - if (!serviceId) return; - if (!activeStakingProgramId) return; - - AutonolasService.getStakingContractInfoByServiceIdStakingProgram( - serviceId, - activeStakingProgramId, - ).then(setActiveStakingContractInfo); - - setIsActiveStakingContractInfoLoaded(true); - }, [activeStakingProgramId, serviceId]); - - /** Updates general staking contract information, not user or service specific */ - const updateStakingContractInfoRecord = async () => { - const stakingPrograms = Object.values([DEFAULT_STAKING_PROGRAM_ID]); - - try { - const stakingInfoPromises = stakingPrograms.map((programId) => - AutonolasService.getStakingContractInfoByStakingProgram(programId), - ); - - const stakingInfos = await Promise.allSettled(stakingInfoPromises); - - const stakingContractInfoRecord = stakingPrograms.reduce( - (record, programId, index) => { - if (stakingInfos[index].status === 'rejected') { - console.error(stakingInfos[index].reason); - return record; - } - record[programId] = stakingInfos[index].value; - return record; - }, - {} as Record>, - ); - - setStakingContractInfoRecord(stakingContractInfoRecord); - setIsStakingContractInfoRecordLoaded(true); - } catch (e) { - console.error({ e }); - } - }; - - useEffect(() => { - updateStakingContractInfoRecord().catch(console.error); - }, []); - - useInterval( - async () => { - await updateStakingContractInfoRecord().catch(console.error); - await updateActiveStakingContractInfo().catch(console.error); - }, - isPaused ? null : FIVE_SECONDS_INTERVAL, - ); - - return ( - - {children} - - ); -}; diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index dcb78765c..f6c2699df 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -1,73 +1,91 @@ -/* - This context provider is responsible for determining the current active staking program, if any. - It does so by checking if the current service is staked, and if so, which staking program it is staked in. - It also provides a method to update the active staking program id in state. -*/ +/** + * This context provider is responsible for determining the current active staking program, if any. + * It does so by checking if the current service is staked, and if so, which staking program it is staked in. + * It also provides a method to update the active staking program id in state. + */ -import { createContext, PropsWithChildren, useCallback, useState } from 'react'; -import { useInterval } from 'usehooks-ts'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { createContext, PropsWithChildren, useCallback } from 'react'; -import { CHAIN_CONFIG } from '@/config/chains'; +import { AGENT_CONFIG } from '@/config/agents'; +import { GNOSIS_CHAIN_CONFIG } from '@/config/chains'; +import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingProgramId } from '@/enums/StakingProgram'; +import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; -import { AutonolasService } from '@/service/Autonolas'; +import { Nullable } from '@/types/Util'; -export const INITIAL_DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.Beta; +export const INITIAL_DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.PearlBeta; export const StakingProgramContext = createContext<{ activeStakingProgramId?: StakingProgramId | null; defaultStakingProgramId: StakingProgramId; - updateActiveStakingProgramId: () => Promise; - setDefaultStakingProgramId: (stakingProgramId: StakingProgramId) => void; }>({ activeStakingProgramId: undefined, defaultStakingProgramId: INITIAL_DEFAULT_STAKING_PROGRAM_ID, - updateActiveStakingProgramId: async () => {}, - setDefaultStakingProgramId: () => {}, }); -/** Determines the current active staking program, if any */ -export const StakingProgramProvider = ({ children }: PropsWithChildren) => { - const { service } = useServices(); +const currentAgent = AGENT_CONFIG.trader; // TODO: replace with dynamic agent selection +const currentChainId = GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with dynamic chain selection - const [activeStakingProgramId, setActiveStakingProgramId] = - useState(); +/** + * hook to get the active staking program id + */ +const useGetActiveStakingProgramId = () => { + const queryClient = useQueryClient(); - const [defaultStakingProgramId, setDefaultStakingProgramId] = useState( - INITIAL_DEFAULT_STAKING_PROGRAM_ID, - ); + const { selectedService, isFetched: isLoaded } = useServices(); + const serviceConfigId = + isLoaded && selectedService ? selectedService?.service_config_id : ''; + const { service } = useService({ serviceConfigId }); - const updateActiveStakingProgramId = useCallback(async () => { - // if no service nft, not staked - const serviceId = - service?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.token; + // if no service nft, not staked + const serviceId = service?.chain_configs[currentChainId].chain_data?.token; + + const response = useQuery({ + queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(currentChainId, serviceId!), + queryFn: async () => { + return await currentAgent.serviceApi.getCurrentStakingProgramByServiceId( + serviceId!, + currentChainId, + ); + // if the response is null, return default staking program id. Thoughts? + }, + enabled: !!serviceId, + refetchInterval: isLoaded ? FIVE_SECONDS_INTERVAL : false, + }); - if ( - !service?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data?.token - ) { - setActiveStakingProgramId(null); - return; - } + const setActiveStakingProgramId = useCallback( + (stakingProgramId: Nullable) => { + if (!serviceId) return; - if (serviceId) { - // if service exists, we need to check if it is staked - AutonolasService.getCurrentStakingProgramByServiceId(serviceId).then( - (stakingProgramId) => { - setActiveStakingProgramId(stakingProgramId); - }, + queryClient.setQueryData( + REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(currentChainId, serviceId), + stakingProgramId, ); - } - }, [service]); + }, + [queryClient, serviceId], + ); + + return { ...response, setActiveStakingProgramId }; +}; - useInterval(updateActiveStakingProgramId, 5000); +/** + * Determines the current active staking program, if any + * */ +export const StakingProgramProvider = ({ children }: PropsWithChildren) => { + const { data: activeStakingProgramId } = useGetActiveStakingProgramId(); return ( {children} diff --git a/frontend/hooks/useAgent.ts b/frontend/hooks/useAgent.ts new file mode 100644 index 000000000..f9ebff42c --- /dev/null +++ b/frontend/hooks/useAgent.ts @@ -0,0 +1,3 @@ +import { AGENT_CONFIG } from '@/config/agents'; + +export const useAgent = () => AGENT_CONFIG.trader; // TODO: replace with dynamic agent selection diff --git a/frontend/hooks/useChainId.ts b/frontend/hooks/useChainId.ts new file mode 100644 index 000000000..2dcff5055 --- /dev/null +++ b/frontend/hooks/useChainId.ts @@ -0,0 +1,3 @@ +import { GNOSIS_CHAIN_CONFIG } from '@/config/chains'; + +export const useChainId = () => GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with dynamic chain selection diff --git a/frontend/hooks/useNotifyOnNewEpoch.ts b/frontend/hooks/useNotifyOnNewEpoch.ts index 11e544aca..e712e81a7 100644 --- a/frontend/hooks/useNotifyOnNewEpoch.ts +++ b/frontend/hooks/useNotifyOnNewEpoch.ts @@ -3,7 +3,7 @@ import { useEffect, useState } from 'react'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; -import { useActiveStakingContractInfo } from './useStakingContractInfo'; +import { useActiveStakingContractInfo } from './useStakingContractDetails'; type EpochStatusNotification = { lastEpoch: number; @@ -18,16 +18,16 @@ export const useNotifyOnNewEpoch = () => { const { showNotification } = useElectronApi(); const { isServiceNotRunning } = useServices(); - const { activeStakingContractInfo, isActiveStakingContractInfoLoaded } = + const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded } = useActiveStakingContractInfo(); - const epoch = activeStakingContractInfo?.epochCounter; + const epoch = activeStakingContractDetails?.epochCounter; const [epochStatusNotification, setEpochStatusNotification] = useState(null); useEffect(() => { // if active staking contract info is not loaded yet, return - if (!isActiveStakingContractInfoLoaded) return; + if (!isActiveStakingContractDetailsLoaded) return; // if agent is running, no need to show notification if (!isServiceNotRunning) return; @@ -56,7 +56,7 @@ export const useNotifyOnNewEpoch = () => { isServiceNotRunning, epochStatusNotification, epoch, - isActiveStakingContractInfoLoaded, + isActiveStakingContractDetailsLoaded, showNotification, ]); }; diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index 1c3c54e41..76e5a6416 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -5,6 +5,7 @@ import { MiddlewareDeploymentStatus } from '@/client'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { Address } from '@/types/Address'; +import { useChainId } from './useChainId'; import { useServices } from './useServices'; type ServiceChainIdAddressRecord = { @@ -80,3 +81,17 @@ export const useService = ({ setDeploymentStatus, }; }; + +/** + * Hook to get service id + */ +export const useServiceId = () => { + const chainId = useChainId(); + const { selectedService, isFetched: isLoaded } = useServices(); + const serviceConfigId = + isLoaded && selectedService ? selectedService?.service_config_id : ''; + const { service } = useService({ serviceConfigId }); + const serviceId = service?.chain_configs[chainId].chain_data?.token; + + return serviceId; +}; diff --git a/frontend/hooks/useStakingContractInfo.ts b/frontend/hooks/useStakingContractDetails.ts similarity index 55% rename from frontend/hooks/useStakingContractInfo.ts rename to frontend/hooks/useStakingContractDetails.ts index bfef377b2..9029f48ef 100644 --- a/frontend/hooks/useStakingContractInfo.ts +++ b/frontend/hooks/useStakingContractDetails.ts @@ -1,43 +1,51 @@ +import { useQuery } from '@tanstack/react-query'; import { isNil } from 'lodash'; import { useContext } from 'react'; -import { StakingContractInfoContext } from '@/context/StakingContractInfoProvider'; +import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { StakingContractDetailsContext } from '@/context/StakingContractDetailsProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; +import { Maybe } from '@/types/Util'; + +import { useAgent } from './useAgent'; +import { useChainId } from './useChainId'; +import { useServiceId } from './useService'; export const useStakingContractContext = () => { const { - activeStakingContractInfo, + activeStakingContractDetails, isPaused, - isStakingContractInfoRecordLoaded, - stakingContractInfoRecord, - updateActiveStakingContractInfo, + isAllStakingContractDetailsRecordLoaded, + allStakingContractDetailsRecord, + refetchActiveStakingContractDetails, setIsPaused, - isActiveStakingContractInfoLoaded, - } = useContext(StakingContractInfoContext); + isActiveStakingContractDetailsLoaded, + } = useContext(StakingContractDetailsContext); return { - isActiveStakingContractInfoLoaded, - activeStakingContractInfo, + isActiveStakingContractDetailsLoaded, + activeStakingContractDetails, isPaused, - isStakingContractInfoRecordLoaded, - stakingContractInfoRecord, - updateActiveStakingContractInfo, + isAllStakingContractDetailsRecordLoaded, + allStakingContractDetailsRecord, + refetchActiveStakingContractDetails, setIsPaused, }; }; export const useActiveStakingContractInfo = () => { const { - activeStakingContractInfo, - isActiveStakingContractInfoLoaded: isActiveStakingContractInfoLoaded, + activeStakingContractDetails, + isActiveStakingContractDetailsLoaded: isActiveStakingContractDetailsLoaded, } = useStakingContractContext(); const { selectedService } = useServices(); // TODO: find a better way to handle this, currently stops react lifecycle hooks being implemented below it - if (!selectedService || !activeStakingContractInfo) + if (!selectedService || !activeStakingContractDetails) return { - stakingContractInfoRecord, - updateActiveStakingContractInfo, + allStakingContractDetailsRecord, + refetchActiveStakingContractDetails, setIsPaused, isPaused, }; @@ -49,7 +57,7 @@ export const useActiveStakingContractInfo = () => { availableRewards, serviceIds, maxNumServices, - } = activeStakingContractInfo ?? {}; + } = activeStakingContractDetails ?? {}; const isAgentEvicted = serviceStakingState === 2; @@ -97,15 +105,48 @@ export const useActiveStakingContractInfo = () => { isServiceStakedForMinimumDuration, isServiceStaked, evictionExpiresAt, - isActiveStakingContractInfoLoaded, - activeStakingContractInfo, + isActiveStakingContractDetailsLoaded, + activeStakingContractDetails, }; }; -export const useStakingContractInfo = (stakingProgramId: StakingProgramId) => { - const { stakingContractInfoRecord } = useStakingContractContext(); +/** + * hook to get staking contract details by staking program + */ +export const useStakingContractDetailsByStakingProgram = ( + stakingProgramId: Maybe, + isPaused?: boolean, +) => { + const serviceId = useServiceId(); + const chainId = useChainId(); + const agent = useAgent(); + + return useQuery({ + queryKey: REACT_QUERY_KEYS.STAKING_CONTRACT_DETAILS_BY_STAKING_PROGRAM_KEY( + chainId, + serviceId!, + stakingProgramId!, + ), + queryFn: async () => { + return await agent.serviceApi.getStakingContractDetailsByServiceIdStakingProgram( + serviceId!, + stakingProgramId!, + chainId, + ); + }, + enabled: !!serviceId && !!stakingProgramId && !!chainId && !isPaused, + refetchInterval: !isPaused ? FIVE_SECONDS_INTERVAL : false, + refetchOnWindowFocus: false, + }); +}; + +export const useStakingContractDetails = ( + stakingProgramId: StakingProgramId, +) => { + const { allStakingContractDetailsRecord } = useStakingContractContext(); - const stakingContractInfo = stakingContractInfoRecord?.[stakingProgramId]; + const stakingContractInfo = + allStakingContractDetailsRecord?.[stakingProgramId]; const { serviceIds, maxNumServices, availableRewards } = stakingContractInfo ?? {}; diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index 7832ff648..d51268448 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -13,12 +13,7 @@ import { * @returns {Object} The active staking program and its metadata. */ export const useStakingProgram = () => { - const { - activeStakingProgramId, - defaultStakingProgramId, - updateActiveStakingProgramId, - setDefaultStakingProgramId, - } = useContext(StakingProgramContext); + const { activeStakingProgramId } = useContext(StakingProgramContext); const isActiveStakingProgramLoaded = activeStakingProgramId !== undefined; @@ -56,7 +51,5 @@ export const useStakingProgram = () => { defaultStakingProgramAddress, defaultStakingProgramMeta, isActiveStakingProgramLoaded, - updateActiveStakingProgramId, - setDefaultStakingProgramId, }; }; diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 373b475e7..6fd28a202 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -16,7 +16,7 @@ import { RewardProvider } from '@/context/RewardProvider'; import { ServicesProvider } from '@/context/ServicesProvider'; import { SettingsProvider } from '@/context/SettingsProvider'; import { SetupProvider } from '@/context/SetupProvider'; -import { StakingContractInfoProvider } from '@/context/StakingContractInfoProvider'; +import { StakingContractDetailsProvider } from '@/context/StakingContractDetailsProvider'; import { StakingProgramProvider } from '@/context/StakingProgramProvider'; import { StoreProvider } from '@/context/StoreProvider'; import { SystemNotificationTriggers } from '@/context/SystemNotificationTriggers'; @@ -44,7 +44,7 @@ export default function App({ Component, pageProps }: AppProps) { - + @@ -66,7 +66,7 @@ export default function App({ Component, pageProps }: AppProps) { - + diff --git a/frontend/service/agents/PredictTrader.ts b/frontend/service/agents/PredictTrader.ts index 880030326..f0012cdad 100644 --- a/frontend/service/agents/PredictTrader.ts +++ b/frontend/service/agents/PredictTrader.ts @@ -6,7 +6,7 @@ import { PROVIDERS } from '@/constants/providers'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; -import { StakingContractInfo, StakingRewardsInfo } from '@/types/Autonolas'; +import { StakingContractDetails, StakingRewardsInfo } from '@/types/Autonolas'; import { ONE_YEAR, StakedAgentService } from './StakedAgentService'; @@ -140,11 +140,11 @@ export abstract class PredictTraderService extends StakedAgentService { ); }; - static getStakingContractInfoByServiceIdStakingProgram = async ( + static getStakingContractDetailsByServiceIdStakingProgram = async ( serviceId: number, stakingProgramId: StakingProgramId, chainId: ChainId = ChainId.Gnosis, - ): Promise | undefined> => { + ): Promise | undefined> => { if (!serviceId) return; const { multicallProvider } = PROVIDERS[chainId]; @@ -197,10 +197,10 @@ export abstract class PredictTraderService extends StakedAgentService { * Get staking contract info by staking program name * eg. Alpha, Beta, Beta2 */ - static getStakingContractInfoByStakingProgram = async ( + static getStakingContractDetailsByName = async ( stakingProgramId: StakingProgramId, chainId: ChainId, - ): Promise> => { + ): Promise> => { const provider = PROVIDERS[chainId].multicallProvider; const { contract: stakingTokenProxy } = diff --git a/frontend/types/Autonolas.ts b/frontend/types/Autonolas.ts index fbb9e0246..fe1695d9f 100644 --- a/frontend/types/Autonolas.ts +++ b/frontend/types/Autonolas.ts @@ -14,7 +14,7 @@ export const StakingRewardsInfoSchema = z.object({ export type StakingRewardsInfo = z.infer; -export type StakingContractInfo = { +export type StakingContractDetails = { availableRewards: number; /* number of slots available for staking */ maxNumServices: number; diff --git a/frontend/types/Util.ts b/frontend/types/Util.ts new file mode 100644 index 000000000..456f55bfc --- /dev/null +++ b/frontend/types/Util.ts @@ -0,0 +1,5 @@ +export type Nullable = T | null; + +export type Optional = T | undefined; + +export type Maybe = Nullable>; From ac040c76b1a58096ab54951bf8feec4067b79359 Mon Sep 17 00:00:00 2001 From: truemiller Date: Mon, 18 Nov 2024 15:27:38 +0000 Subject: [PATCH 232/463] refactor: export explicitally for dx --- frontend/hooks/useWallet.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/hooks/useWallet.ts b/frontend/hooks/useWallet.ts index 3ac343b60..562d693c9 100644 --- a/frontend/hooks/useWallet.ts +++ b/frontend/hooks/useWallet.ts @@ -2,4 +2,9 @@ import { useContext } from 'react'; import { WalletContext } from '@/context/WalletProvider'; -export const useWallet = () => useContext(WalletContext); +export const useWallet = () => { + const { wallets, setPaused, paused, togglePaused, refetch } = + useContext(WalletContext); + + return { wallets, setPaused, paused, togglePaused, refetch }; +}; From 91a972df1bac8a8a5c3a91fa03d440db856ebc36 Mon Sep 17 00:00:00 2001 From: Mohan Date: Mon, 18 Nov 2024 22:28:17 +0530 Subject: [PATCH 233/463] feat: use default staking contract as a fallback when the active staking contract is unavailable and fetched from the backend (#462) * feat: Update Gnosis staking program contract addresses and refactor usage * feat: Add Optimism staking program contract addresses and refactor staking program configuration * feat: Refactor staking program hooks and constants for improved clarity and functionality * feat: Simplify staking program ID usage in RewardProvider context * feat: Update rewards query keys and add rewards history key for improved data fetching * feat: Clean up useStakingProgram hook by removing unused default staking program metadata * feat: Refactor staking program hooks to improve clarity and functionality, including dynamic agent and chain selection --- .../StakingRewardsThisEpoch.tsx | 11 +- frontend/config/stakingPrograms/gnosis.ts | 31 +++- frontend/config/stakingPrograms/index.ts | 24 ++- frontend/config/stakingPrograms/optimism.ts | 12 +- frontend/constants/react-query-keys.ts | 10 +- frontend/context/RewardProvider.tsx | 22 +-- frontend/context/StakingProgramProvider.tsx | 74 ++++---- frontend/hooks/useRewardsHistory.ts | 159 ++++++++++-------- frontend/hooks/useService.ts | 1 + frontend/hooks/useStakingProgram.ts | 55 ++---- frontend/service/agents/StakedAgentService.ts | 23 ++- 11 files changed, 238 insertions(+), 184 deletions(-) diff --git a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx index 1ea39be0f..c6796dcfa 100644 --- a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx @@ -2,8 +2,10 @@ import { InfoCircleOutlined } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; import { Popover, Typography } from 'antd'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { POPOVER_WIDTH_MEDIUM } from '@/constants/width'; import { getLatestEpochDetails } from '@/graphql/queries'; +import { useChainId } from '@/hooks/useChainId'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { formatToTime } from '@/utils/time'; @@ -11,17 +13,22 @@ const { Text } = Typography; const useEpochEndTime = () => { const { activeStakingProgramAddress } = useStakingProgram(); + const chainId = useChainId(); const { data, isLoading } = useQuery({ - queryKey: ['latestEpochTime'], + queryKey: REACT_QUERY_KEYS.LATEST_EPOCH_TIME_KEY( + chainId, + activeStakingProgramAddress!, + ), queryFn: async () => { - return await getLatestEpochDetails(activeStakingProgramAddress as string); + return await getLatestEpochDetails(activeStakingProgramAddress!); }, select: (data) => { // last epoch end time + epoch length return Number(data.blockTimestamp) + Number(data.epochLength); }, enabled: !!activeStakingProgramAddress, + refetchOnWindowFocus: false, }); return { data, isLoading }; diff --git a/frontend/config/stakingPrograms/gnosis.ts b/frontend/config/stakingPrograms/gnosis.ts index 776b91d20..d53dd3349 100644 --- a/frontend/config/stakingPrograms/gnosis.ts +++ b/frontend/config/stakingPrograms/gnosis.ts @@ -5,11 +5,26 @@ import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; +import { Address } from '@/types/Address'; import { ACTIVITY_CHECKERS } from '../activityCheckers'; import { MECHS, MechType } from '../mechs'; import { StakingProgramMap } from '.'; +export const GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record< + string, + Address +> = { + [StakingProgramId.PearlAlpha]: '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A', + [StakingProgramId.PearlBeta]: '0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d', + [StakingProgramId.PearlBeta2]: '0x1c2F82413666d2a3fD8bC337b0268e62dDF67434', + [StakingProgramId.PearlBeta3]: '0xBd59Ff0522aA773cB6074ce83cD1e4a05A457bc1', + [StakingProgramId.PearlBeta4]: '0x3052451e1eAee78e62E169AfdF6288F8791F2918', + [StakingProgramId.PearlBeta5]: '0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4', + [StakingProgramId.PearlBetaMechMarketplace]: + '0xDaF34eC46298b53a3d24CBCb431E84eBd23927dA', +}; + export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { [StakingProgramId.PearlAlpha]: { deprecated: true, @@ -22,7 +37,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( - '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A', + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlAlpha], STAKING_TOKEN_PROXY_ABI, ), }, @@ -36,7 +51,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( - '0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d', + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta], STAKING_TOKEN_PROXY_ABI, ), }, @@ -50,7 +65,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( - '0x1c2F82413666d2a3fD8bC337b0268e62dDF67434', + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta2], STAKING_TOKEN_PROXY_ABI, ), }, @@ -64,7 +79,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( - '0xBd59Ff0522aA773cB6074ce83cD1e4a05A457bc1', + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta3], STAKING_TOKEN_PROXY_ABI, ), }, @@ -78,7 +93,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( - '0x3052451e1eAee78e62E169AfdF6288F8791F2918', + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta4], STAKING_TOKEN_PROXY_ABI, ), }, @@ -92,7 +107,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( - '0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4', + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta5], STAKING_TOKEN_PROXY_ABI, ), }, @@ -106,7 +121,9 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { mech: MECHS[ChainId.Gnosis][MechType.Marketplace].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Marketplace], contract: new MulticallContract( - '0xDaF34eC46298b53a3d24CBCb431E84eBd23927dA', + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + StakingProgramId.PearlBetaMechMarketplace + ], STAKING_TOKEN_PROXY_ABI, ), }, diff --git a/frontend/config/stakingPrograms/index.ts b/frontend/config/stakingPrograms/index.ts index 1c9dd6919..a1688303a 100644 --- a/frontend/config/stakingPrograms/index.ts +++ b/frontend/config/stakingPrograms/index.ts @@ -2,9 +2,16 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; +import { Address } from '@/types/Address'; -import { GNOSIS_STAKING_PROGRAMS } from './gnosis'; -import { OPTIMISM_STAKING_PROGRAMS } from './optimism'; +import { + GNOSIS_STAKING_PROGRAMS, + GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES, +} from './gnosis'; +import { + OPTIMISM_STAKING_PROGRAMS, + OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, +} from './optimism'; /** * Single non-chain specific staking program configuration @@ -26,11 +33,16 @@ export type StakingProgramMap = { [stakingProgramId: string]: StakingProgramConfig; }; -export type StakingProgramMapByChains = { +export const STAKING_PROGRAMS: { [chainId: number | ChainId]: StakingProgramMap; -}; - -export const STAKING_PROGRAMS: StakingProgramMapByChains = { +} = { [ChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS, [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS, }; + +export const STAKING_PROGRAM_ADDRESS: { + [chainId: number | ChainId]: Record; +} = { + [ChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES, + [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, +}; diff --git a/frontend/config/stakingPrograms/optimism.ts b/frontend/config/stakingPrograms/optimism.ts index 12d8172b9..9499f0720 100644 --- a/frontend/config/stakingPrograms/optimism.ts +++ b/frontend/config/stakingPrograms/optimism.ts @@ -11,11 +11,19 @@ import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; +import { Address } from '@/types/Address'; import { ACTIVITY_CHECKERS } from '../activityCheckers'; import { MECHS, MechType } from '../mechs'; import { StakingProgramMap } from '.'; +export const OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record< + string, + Address +> = { + [StakingProgramId.OptimusAlpha]: '0x88996bbdE7f982D93214881756840cE2c77C4992', +}; + export const OPTIMISM_STAKING_PROGRAMS: StakingProgramMap = { [StakingProgramId.OptimusAlpha]: { name: 'Optimus Alpha', @@ -27,7 +35,9 @@ export const OPTIMISM_STAKING_PROGRAMS: StakingProgramMap = { activityChecker: ACTIVITY_CHECKERS[ChainId.Optimism][MechType.Agent], chainId: ChainId.Optimism, contract: new MulticallContract( - '0x88996bbdE7f982D93214881756840cE2c77C4992', + OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ + StakingProgramId.OptimusAlpha + ], STAKING_TOKEN_PROXY_ABI, ), }, diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index 89279af23..4592ad2aa 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -24,10 +24,14 @@ export const REACT_QUERY_KEYS = { // wallets WALLETS_KEY: ['wallets'] as const, + // epoch + LATEST_EPOCH_TIME_KEY: (chainId: number, stakingProgramId: string) => + ['latestEpochTime', chainId, stakingProgramId] as const, + // rewards REWARDS_KEY: ( chainId: number, - serviceUuid: string, + serviceConfigId: string, stakingProgramId: string, multisig: string, token: number, @@ -35,7 +39,7 @@ export const REACT_QUERY_KEYS = { [ 'rewards', chainId, - serviceUuid, + serviceConfigId, stakingProgramId, multisig, token, @@ -53,4 +57,6 @@ export const REACT_QUERY_KEYS = { stakingProgramId, chainId, ] as const, + REWARDS_HISTORY_KEY: (chainId: number, serviceId: number) => + ['rewardsHistory', chainId, serviceId] as const, } as const; diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index 192b82a87..ec1c31deb 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -48,10 +48,7 @@ const currentChainId = GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with dynami */ const useStakingRewardsDetails = () => { const { isOnline } = useContext(OnlineStatusContext); - const { activeStakingProgramId, defaultStakingProgramId } = useContext( - StakingProgramContext, - ); - const stakingProgramId = activeStakingProgramId ?? defaultStakingProgramId; + const { activeStakingProgramId } = useContext(StakingProgramContext); const { selectedService, isFetched: isLoaded } = useServices(); const serviceConfigId = @@ -67,7 +64,7 @@ const useStakingRewardsDetails = () => { queryKey: REACT_QUERY_KEYS.REWARDS_KEY( currentChainId, serviceConfigId, - stakingProgramId!, + activeStakingProgramId!, multisig!, token!, ), @@ -76,13 +73,13 @@ const useStakingRewardsDetails = () => { { agentMultisigAddress: multisig!, serviceId: token!, - stakingProgramId: stakingProgramId!, + stakingProgramId: activeStakingProgramId!, chainId: currentChainId, }, ); return StakingRewardsInfoSchema.parse(response); }, - enabled: !!isOnline && !!stakingProgramId && !!multisig && !!token, + enabled: !!isOnline && !!activeStakingProgramId && !!multisig && !!token, refetchInterval: isOnline ? FIVE_SECONDS_INTERVAL : false, refetchOnWindowFocus: false, }); @@ -93,10 +90,7 @@ const useStakingRewardsDetails = () => { */ const useAvailableRewardsForEpoch = () => { const { isOnline } = useContext(OnlineStatusContext); - const { activeStakingProgramId, defaultStakingProgramId } = useContext( - StakingProgramContext, - ); - const stakingProgramId = activeStakingProgramId ?? defaultStakingProgramId; + const { activeStakingProgramId } = useContext(StakingProgramContext); const { selectedService, isFetched: isLoaded } = useServices(); const serviceConfigId = @@ -106,16 +100,16 @@ const useAvailableRewardsForEpoch = () => { queryKey: REACT_QUERY_KEYS.AVAILABLE_REWARDS_FOR_EPOCH_KEY( currentChainId, serviceConfigId, - stakingProgramId!, + activeStakingProgramId!, currentChainId, ), queryFn: async () => { return await currentAgent.serviceApi.getAvailableRewardsForEpoch( - stakingProgramId, + activeStakingProgramId!, currentChainId, ); }, - enabled: !!isOnline && !!stakingProgramId, + enabled: !!isOnline && !!activeStakingProgramId, refetchInterval: isOnline ? FIVE_SECONDS_INTERVAL : false, refetchOnWindowFocus: false, }); diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index f6c2699df..684a2bd56 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -1,59 +1,47 @@ -/** - * This context provider is responsible for determining the current active staking program, if any. - * It does so by checking if the current service is staked, and if so, which staking program it is staked in. - * It also provides a method to update the active staking program id in state. - */ - import { useQuery, useQueryClient } from '@tanstack/react-query'; import { createContext, PropsWithChildren, useCallback } from 'react'; -import { AGENT_CONFIG } from '@/config/agents'; -import { GNOSIS_CHAIN_CONFIG } from '@/config/chains'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useService } from '@/hooks/useService'; -import { useServices } from '@/hooks/useServices'; +import { useAgent } from '@/hooks/useAgent'; +import { useChainId } from '@/hooks/useChainId'; +import { useServiceId } from '@/hooks/useService'; import { Nullable } from '@/types/Util'; export const INITIAL_DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.PearlBeta; export const StakingProgramContext = createContext<{ - activeStakingProgramId?: StakingProgramId | null; - defaultStakingProgramId: StakingProgramId; + isActiveStakingProgramLoaded: boolean; + activeStakingProgramId?: Nullable; }>({ - activeStakingProgramId: undefined, - defaultStakingProgramId: INITIAL_DEFAULT_STAKING_PROGRAM_ID, + isActiveStakingProgramLoaded: false, + activeStakingProgramId: null, }); -const currentAgent = AGENT_CONFIG.trader; // TODO: replace with dynamic agent selection -const currentChainId = GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with dynamic chain selection - /** * hook to get the active staking program id */ const useGetActiveStakingProgramId = () => { const queryClient = useQueryClient(); - - const { selectedService, isFetched: isLoaded } = useServices(); - const serviceConfigId = - isLoaded && selectedService ? selectedService?.service_config_id : ''; - const { service } = useService({ serviceConfigId }); - - // if no service nft, not staked - const serviceId = service?.chain_configs[currentChainId].chain_data?.token; + const agent = useAgent(); + const chainId = useChainId(); + const serviceId = useServiceId(); const response = useQuery({ - queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(currentChainId, serviceId!), + queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(chainId, serviceId!), queryFn: async () => { - return await currentAgent.serviceApi.getCurrentStakingProgramByServiceId( - serviceId!, - currentChainId, - ); - // if the response is null, return default staking program id. Thoughts? + const response = + await agent.serviceApi.getCurrentStakingProgramByServiceId( + serviceId!, + chainId, + ); + return response?.length === 0 + ? INITIAL_DEFAULT_STAKING_PROGRAM_ID + : response; }, - enabled: !!serviceId, - refetchInterval: isLoaded ? FIVE_SECONDS_INTERVAL : false, + enabled: !!chainId && !!serviceId, + refetchInterval: serviceId ? FIVE_SECONDS_INTERVAL : false, }); const setActiveStakingProgramId = useCallback( @@ -61,31 +49,31 @@ const useGetActiveStakingProgramId = () => { if (!serviceId) return; queryClient.setQueryData( - REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(currentChainId, serviceId), + REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(chainId, serviceId), stakingProgramId, ); }, - [queryClient, serviceId], + [queryClient, chainId, serviceId], ); return { ...response, setActiveStakingProgramId }; }; /** - * Determines the current active staking program, if any - * */ + * context provider responsible for determining the current active staking program, if any. + * It does so by checking if the current service is staked, and if so, which staking program it is staked in. + * It also provides a method to update the active staking program id in state. + */ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { - const { data: activeStakingProgramId } = useGetActiveStakingProgramId(); + const { isLoading: isStakingProgramLoading, data: activeStakingProgramId } = + useGetActiveStakingProgramId(); return ( {children} diff --git a/frontend/hooks/useRewardsHistory.ts b/frontend/hooks/useRewardsHistory.ts index e2e8dd96e..28c5db6c8 100644 --- a/frontend/hooks/useRewardsHistory.ts +++ b/frontend/hooks/useRewardsHistory.ts @@ -2,15 +2,18 @@ import { useQuery } from '@tanstack/react-query'; import { ethers } from 'ethers'; import { gql, request } from 'graphql-request'; import { groupBy } from 'lodash'; -import { useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; import { z } from 'zod'; -import { GNOSIS_SERVICE_STAKING_CONTRACT_ADDRESSES } from '@/constants/contractAddresses'; +import { STAKING_PROGRAM_ADDRESS } from '@/config/stakingPrograms'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { GNOSIS_REWARDS_HISTORY_SUBGRAPH_URL } from '@/constants/urls'; import { Address } from '@/types/Address'; -import { getStakingProgramIdByAddress } from '@/utils/service'; +import { Nullable } from '@/types/Util'; -import { useServices } from './useServices'; +import { useAgent } from './useAgent'; +import { useChainId } from './useChainId'; +import { useServiceId } from './useService'; const ONE_DAY_IN_S = 24 * 60 * 60; const ONE_DAY_IN_MS = ONE_DAY_IN_S * 1000; @@ -41,11 +44,12 @@ const CheckpointGraphResponseSchema = z.object({ const CheckpointsGraphResponseSchema = z.array(CheckpointGraphResponseSchema); type CheckpointResponse = z.infer; -const supportedStakingContracts = Object.values( - GNOSIS_SERVICE_STAKING_CONTRACT_ADDRESSES, -).map((address) => `"${address}"`); +const fetchRewardsQuery = (chainId: number) => { + const supportedStakingContracts = Object.values( + STAKING_PROGRAM_ADDRESS[chainId], + ).map((address) => `"${address}"`); -const fetchRewardsQuery = gql` + return gql` { checkpoints( orderBy: epoch @@ -68,6 +72,7 @@ const fetchRewardsQuery = gql` } } `; +}; export type Checkpoint = { epoch: string; @@ -77,68 +82,80 @@ export type Checkpoint = { transactionHash: string; epochLength: string; contractAddress: string; - contractName?: string; + contractName: Nullable; epochEndTimeStamp: number; epochStartTimeStamp: number; reward: number; earned: boolean; }; -const transformCheckpoints = ( - checkpoints: CheckpointResponse[], - serviceId: number, - timestampToIgnore?: null | number, -): Checkpoint[] => { - if (!checkpoints || checkpoints.length === 0) return []; - if (!serviceId) return []; - - return checkpoints - .map((checkpoint: CheckpointResponse, index: number) => { - const serviceIdIndex = - checkpoint.serviceIds?.findIndex((id) => Number(id) === serviceId) ?? - -1; - - let reward = '0'; - - if (serviceIdIndex !== -1) { - const currentReward = checkpoint.rewards?.[serviceIdIndex]; - const isRewardFinite = isFinite(Number(currentReward)); - reward = isRewardFinite ? currentReward ?? '0' : '0'; - } - - // If the epoch is 0, it means it's the first epoch else, - // the start time of the epoch is the end time of the previous epoch - const epochStartTimeStamp = - checkpoint.epoch === '0' - ? Number(checkpoint.blockTimestamp) - Number(checkpoint.epochLength) - : checkpoints[index + 1]?.blockTimestamp ?? 0; - - const stakingContractId = getStakingProgramIdByAddress( - checkpoint.contractAddress as Address, - ); +const useTransformCheckpoints = () => { + const agent = useAgent(); + const chainId = useChainId(); + + return useCallback( + ( + serviceId: number, + checkpoints: CheckpointResponse[], + timestampToIgnore?: null | number, + ) => { + if (!checkpoints || checkpoints.length === 0) return []; + if (!serviceId) return []; - return { - ...checkpoint, - epochEndTimeStamp: Number(checkpoint.blockTimestamp ?? Date.now()), - epochStartTimeStamp: Number(epochStartTimeStamp), - reward: Number(ethers.utils.formatUnits(reward, 18)), - earned: serviceIdIndex !== -1, - contractName: stakingContractId, - }; - }) - .filter((checkpoint) => { - // If the contract has been switched to new contract, - // ignore the rewards from the old contract of the same epoch, - // as the rewards are already accounted in the new contract. - // Example: If contract was switched on September 1st, 2024, - // ignore the rewards before that date in the old contract. - if (!timestampToIgnore) return true; - - if (!checkpoint) return false; - if (!checkpoint.epochEndTimeStamp) return false; - - return checkpoint.epochEndTimeStamp < timestampToIgnore; - }); + return checkpoints + .map((checkpoint: CheckpointResponse, index: number) => { + const serviceIdIndex = + checkpoint.serviceIds?.findIndex( + (id) => Number(id) === serviceId, + ) ?? -1; + + let reward = '0'; + + if (serviceIdIndex !== -1) { + const currentReward = checkpoint.rewards?.[serviceIdIndex]; + const isRewardFinite = isFinite(Number(currentReward)); + reward = isRewardFinite ? currentReward ?? '0' : '0'; + } + + // If the epoch is 0, it means it's the first epoch else, + // the start time of the epoch is the end time of the previous epoch + const epochStartTimeStamp = + checkpoint.epoch === '0' + ? Number(checkpoint.blockTimestamp) - + Number(checkpoint.epochLength) + : checkpoints[index + 1]?.blockTimestamp ?? 0; + + const stakingContractId = + agent.serviceApi.getStakingProgramIdByAddress( + chainId, + checkpoint.contractAddress as Address, + ); + + return { + ...checkpoint, + epochEndTimeStamp: Number(checkpoint.blockTimestamp ?? Date.now()), + epochStartTimeStamp: Number(epochStartTimeStamp), + reward: Number(ethers.utils.formatUnits(reward, 18)), + earned: serviceIdIndex !== -1, + contractName: stakingContractId, + }; + }) + .filter((checkpoint) => { + // If the contract has been switched to new contract, + // ignore the rewards from the old contract of the same epoch, + // as the rewards are already accounted in the new contract. + // Example: If contract was switched on September 1st, 2024, + // ignore the rewards before that date in the old contract. + if (!timestampToIgnore) return true; + + if (!checkpoint) return false; + if (!checkpoint.epochEndTimeStamp) return false; + + return checkpoint.epochEndTimeStamp < timestampToIgnore; + }); + }, + [agent, chainId], + ); }; type CheckpointsResponse = { checkpoints: CheckpointResponse[] }; @@ -147,16 +164,18 @@ type CheckpointsResponse = { checkpoints: CheckpointResponse[] }; * hook to fetch rewards history for all contracts */ const useContractCheckpoints = () => { - const { serviceId } = useServices(); + const serviceId = useServiceId(); + const chainId = useChainId(); + const transformCheckpoints = useTransformCheckpoints(); return useQuery({ - queryKey: [], + queryKey: REACT_QUERY_KEYS.REWARDS_HISTORY_KEY(chainId, serviceId!), async queryFn() { if (!serviceId) return []; const checkpointsResponse = await request( GNOSIS_REWARDS_HISTORY_SUBGRAPH_URL, - fetchRewardsQuery, + fetchRewardsQuery(chainId), ); const parsedCheckpoints = CheckpointsGraphResponseSchema.safeParse( @@ -201,22 +220,22 @@ const useContractCheckpoints = () => { // transform the checkpoints, includes epoch start and end time, rewards, etc const transformedCheckpoints = transformCheckpoints( - checkpoints, serviceId, + checkpoints, null, ); return { ...acc, [stakingContractAddress]: transformedCheckpoints }; }, {}); }, - refetchOnWindowFocus: false, + enabled: !!chainId && !!serviceId, refetchInterval: ONE_DAY_IN_MS, - enabled: !!serviceId, + refetchOnWindowFocus: false, }); }; export const useRewardsHistory = () => { - const { serviceId } = useServices(); + const serviceId = useServiceId(); const { isError, isLoading, diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index 76e5a6416..d789f3fbc 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -82,6 +82,7 @@ export const useService = ({ }; }; +// TODO: support multiple services /** * Hook to get service id */ diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index d51268448..fdcfdd209 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -1,55 +1,34 @@ import { useContext, useMemo } from 'react'; -import { MiddlewareChain } from '@/client'; -import { SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES } from '@/config/olasContracts'; -import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; -import { - DEFAULT_STAKING_PROGRAM_ID, - StakingProgramContext, -} from '@/context/StakingProgramProvider'; +import { STAKING_PROGRAM_ADDRESS } from '@/config/stakingPrograms'; +import { GNOSIS_STAKING_PROGRAMS } from '@/config/stakingPrograms/gnosis'; +import { StakingProgramContext } from '@/context/StakingProgramProvider'; + +import { useChainId } from './useChainId'; /** - * Hook to get the active staking program and its metadata, and the default staking program. - * @returns {Object} The active staking program and its metadata. + * Hook to get the active staking program and its metadata. */ export const useStakingProgram = () => { - const { activeStakingProgramId } = useContext(StakingProgramContext); - - const isActiveStakingProgramLoaded = activeStakingProgramId !== undefined; + const chainId = useChainId(); + const { activeStakingProgramId, isActiveStakingProgramLoaded } = useContext( + StakingProgramContext, + ); - /** - * TODO: implement enums - * returns `StakingProgramMeta` if defined - * returns `undefined` if not loaded - * returns `null` if not actively staked - */ const activeStakingProgramMeta = useMemo(() => { - if (activeStakingProgramId === undefined) return; - if (activeStakingProgramId === null) return null; - return STAKING_PROGRAM_META[activeStakingProgramId]; + if (!activeStakingProgramId) return null; + return GNOSIS_STAKING_PROGRAMS[activeStakingProgramId]; }, [activeStakingProgramId]); - const defaultStakingProgramMeta = - STAKING_PROGRAM_META[DEFAULT_STAKING_PROGRAM_ID]; - const activeStakingProgramAddress = useMemo(() => { - if (!activeStakingProgramId) return; - return SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[ - MiddlewareChain.OPTIMISM - ][activeStakingProgramId]; - }, [activeStakingProgramId]); - - const defaultStakingProgramAddress = - SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[ - MiddlewareChain.OPTIMISM - ][DEFAULT_STAKING_PROGRAM_ID]; + if (!activeStakingProgramId) return null; + return STAKING_PROGRAM_ADDRESS[chainId][activeStakingProgramId]; + }, [chainId, activeStakingProgramId]); return { - activeStakingProgramAddress, + isActiveStakingProgramLoaded, activeStakingProgramId, + activeStakingProgramAddress, activeStakingProgramMeta, - defaultStakingProgramAddress, - defaultStakingProgramMeta, - isActiveStakingProgramLoaded, }; }; diff --git a/frontend/service/agents/StakedAgentService.ts b/frontend/service/agents/StakedAgentService.ts index a10a34cfc..186a8d462 100644 --- a/frontend/service/agents/StakedAgentService.ts +++ b/frontend/service/agents/StakedAgentService.ts @@ -11,13 +11,17 @@ import { ethers } from 'ethers'; import { Contract as MulticallContract } from 'ethers-multicall'; import { OLAS_CONTRACTS } from '@/config/olasContracts'; -import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; +import { + STAKING_PROGRAM_ADDRESS, + STAKING_PROGRAMS, +} from '@/config/stakingPrograms'; import { PROVIDERS } from '@/constants/providers'; import { ChainId } from '@/enums/Chain'; import { ContractType } from '@/enums/Contract'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; +import { Nullable } from '@/types/Util'; export const ONE_YEAR = 1 * 24 * 60 * 60 * 365; @@ -131,4 +135,21 @@ export abstract class StakedAgentService { serviceState, }; }; + + /** + * + * Get the staking program id by address + * @example getStakingProgramIdByAddress('0x3052451e1eAee78e62E169AfdF6288F8791F2918') // StakingProgramId.Beta4 + */ + static getStakingProgramIdByAddress = ( + chainId: number | ChainId, + contractAddress: Address, + ): Nullable => { + const addresses = STAKING_PROGRAM_ADDRESS[chainId]; + const entries = Object.entries(addresses) as [StakingProgramId, Address][]; + const foundEntry = entries.find( + ([, address]) => address.toLowerCase() === contractAddress.toLowerCase(), + ); + return foundEntry ? foundEntry[0] : null; + }; } From b7ae1071510564ef78d37b61b83823c88b61a5d2 Mon Sep 17 00:00:00 2001 From: truemiller Date: Mon, 18 Nov 2024 23:59:05 +0000 Subject: [PATCH 234/463] feat: extend wallet types --- frontend/enums/Wallet.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts index 9d9ee2a1d..2db21b9f8 100644 --- a/frontend/enums/Wallet.ts +++ b/frontend/enums/Wallet.ts @@ -22,6 +22,8 @@ export type MasterSafe = Omit & { chainId: ChainId; }; +export type MasterWallet = MasterEoa | MasterSafe; + export type AgentEoa = { address: Address; type: WalletType.EOA; @@ -33,6 +35,11 @@ export type AgentSafe = Omit & { chainId: ChainId; }; -export type MasterWallets = (MasterEoa | MasterSafe)[]; -export type AgentWallets = (AgentEoa | AgentSafe)[]; -export type Wallets = (MasterEoa | MasterSafe | AgentEoa | AgentSafe)[]; +export type AgentWallet = AgentEoa | AgentSafe; + +export type Wallet = MasterWallet | AgentWallet; + +export type MasterWallets = MasterWallet[]; +export type AgentWallets = AgentWallet[]; + +export type Wallets = Wallet[]; From b15c2581d8d8da8e41f91f9c637a736cb04dd941 Mon Sep 17 00:00:00 2001 From: truemiller Date: Mon, 18 Nov 2024 23:59:14 +0000 Subject: [PATCH 235/463] feat: add token config types --- frontend/config/tokens.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index 12d4b9a46..475ce6497 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -23,8 +23,10 @@ export type NativeTokenConfig = { decimals: number; }; +export type TokenConfig = Erc20TokenConfig | NativeTokenConfig; + export type ChainTokenConfig = { - [tokenSymbol: string]: Erc20TokenConfig | NativeTokenConfig; + [tokenSymbol: string]: TokenConfig; }; export const GNOSIS_TOKEN_CONFIG: ChainTokenConfig = { From 59c5e1dac9aec8a2d0ded8da338f8f2238ee49e1 Mon Sep 17 00:00:00 2001 From: truemiller Date: Mon, 18 Nov 2024 23:59:34 +0000 Subject: [PATCH 236/463] refactor: chainIdKey name --- frontend/constants/providers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/constants/providers.ts b/frontend/constants/providers.ts index 3d9f3d626..0cf4991d3 100644 --- a/frontend/constants/providers.ts +++ b/frontend/constants/providers.ts @@ -4,7 +4,7 @@ import { Provider as MulticallProvider } from 'ethers-multicall'; import { CHAIN_CONFIG } from '../config/chains'; type Providers = { - [chainConfigsKey in keyof typeof CHAIN_CONFIG]: { + [chainIdKey in keyof typeof CHAIN_CONFIG]: { provider: ethers.providers.JsonRpcProvider; multicallProvider: MulticallProvider; }; From 31feb3f7d92cba8ef0b90a176817dec9e5aeb362 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 00:01:11 +0000 Subject: [PATCH 237/463] feat: all wallet native and erc20 balances --- frontend/context/BalanceProvider.tsx | 372 ++++++++++++--------------- 1 file changed, 164 insertions(+), 208 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 746a42b81..4785bd391 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -1,6 +1,8 @@ import { message } from 'antd'; +import { BigNumberish } from 'ethers'; import { isAddress } from 'ethers/lib/utils'; -import { isNil, isNumber } from 'lodash'; +import { Contract as MulticallContract } from 'ethers-multicall'; +import { isNil } from 'lodash'; import { ValueOf } from 'next/dist/shared/lib/constants'; import { createContext, @@ -14,10 +16,11 @@ import { } from 'react'; import { useInterval } from 'usehooks-ts'; -import { MiddlewareWalletResponse } from '@/client'; +import { ERC20_BALANCE_OF_STRING_FRAGMENT } from '@/abis/erc20'; import { CHAIN_CONFIG } from '@/config/chains'; -import { TOKEN_CONFIG } from '@/config/tokens'; +import { TOKEN_CONFIG, TokenType } from '@/config/tokens'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { PROVIDERS } from '@/constants/providers'; import { LOW_AGENT_SAFE_BALANCE, LOW_MASTER_SAFE_BALANCE, @@ -25,19 +28,13 @@ import { import { ChainId } from '@/enums/Chain'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { TokenSymbol } from '@/enums/Token'; -import { Wallets } from '@/enums/Wallet'; +import { Wallets, WalletType } from '@/enums/Wallet'; import { useServices } from '@/hooks/useServices'; import { StakedAgentService } from '@/service/agents/StakedAgentService'; -import { EthersService } from '@/service/Ethers'; -import MulticallService from '@/service/Multicall'; import { Address } from '@/types/Address'; -import { - AddressNumberRecord, - WalletAddressNumberRecord, -} from '@/types/Records'; +import { WalletAddressNumberRecord } from '@/types/Records'; import { OnlineStatusContext } from './OnlineStatusProvider'; -import { RewardContext } from './RewardProvider'; import { WalletContext } from './WalletProvider'; export const BalanceContext = createContext<{ @@ -64,8 +61,6 @@ export const BalanceContext = createContext<{ isBalanceLoaded: false, olasBondBalance: undefined, olasDepositBalance: undefined, - masterEoaBalance: undefined, - masterSafeBalance: undefined, totalEthBalance: undefined, totalOlasBalance: undefined, isLowBalance: false, @@ -76,106 +71,66 @@ export const BalanceContext = createContext<{ updateBalances: async () => {}, setIsPaused: () => {}, totalOlasStakedBalance: undefined, - baseBalance: undefined, - ethereumBalance: undefined, - optimismBalance: undefined, }); export const BalanceProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); const { wallets } = useContext(WalletContext); const { services, serviceAddresses } = useServices(); - const { optimisticRewardsEarnedForEpoch, accruedServiceStakingRewards } = - useContext(RewardContext); + // const { optimisticRewardsEarnedForEpoch, accruedServiceStakingRewards } = + // useContext(RewardContext); const [isLoaded, setIsLoaded] = useState(false); const [isPaused, setIsPaused] = useState(false); - const [olasDepositBalance, setOlasDepositBalance] = useState(); - const [olasBondBalance, setOlasBondBalance] = useState(); + const [isBalanceLoaded, setIsBalanceLoaded] = useState(false); - const [walletBalances, setWalletBalances] = - useState({}); - - // TODO: refactor to support multiple chains, and gas tokens from config - const totalEthBalance: number | undefined = useMemo(() => { - if (!isLoaded) return; - return Object.values(walletBalances).reduce( - (acc: number, walletBalance) => acc + walletBalance.ETH, - 0, - ); - }, [isLoaded, walletBalances]); - - const totalOlasBalance: number | undefined = useMemo(() => { - if (!isLoaded) return; - - const sumWalletBalances = Object.values(walletBalances).reduce( - (acc: number, walletBalance) => acc + walletBalance.OLAS, - 0, - ); - - const total = - sumWalletBalances + - (olasDepositBalance ?? 0) + - (olasBondBalance ?? 0) + - (optimisticRewardsEarnedForEpoch ?? 0) + - (accruedServiceStakingRewards ?? 0); - - return total; - }, [ - accruedServiceStakingRewards, - isLoaded, - olasBondBalance, - olasDepositBalance, - optimisticRewardsEarnedForEpoch, - walletBalances, - ]); - - const totalOlasStakedBalance: number | undefined = useMemo(() => { - if (!isLoaded) return; - return (olasBondBalance ?? 0) + (olasDepositBalance ?? 0); - }, [isLoaded, olasBondBalance, olasDepositBalance]); - const updateBalances = useCallback(async (): Promise => { - if (!masterEoaAddress) return; + const [walletBalances, setWalletBalances] = useState([]); - const walletAddresses: Address[] = []; - if (isAddress(masterEoaAddress)) walletAddresses.push(masterEoaAddress); - if (isAddress(`${masterSafeAddress}`)) { - walletAddresses.push(masterSafeAddress as Address); - } - if (serviceAddresses) { - walletAddresses.push(...serviceAddresses.filter(isAddress)); - } + // // TODO: refactor to support multiple chains, and gas tokens from config + // const totalEthBalance: number | undefined = useMemo(() => { + // if (!isLoaded) return; + // return Object.values(walletBalances).reduce( + // (acc: number, walletBalance) => acc + walletBalance.ETH, + // 0, + // ); + // }, [isLoaded, walletBalances]); - // fetch balances for other chains - // TODO: refactor to dynamically fetch balances for all chains - // try { - // await Promise.allSettled([ - // baseBalanceTemp, - // ethereumBalanceTemp, - // optimismBalanceTemp, - // ]); - // } catch (error) { - // console.error(error); - // } + // const totalOlasBalance: number | undefined = useMemo(() => { + // if (!isLoaded) return; - try { - const walletBalances = await getWalletBalances(walletAddresses); - if (!walletBalances) return; + // const sumWalletBalances = Object.values(walletBalances).reduce( + // (acc: number, walletBalance) => acc + walletBalance.OLAS, + // 0, + // ); + + // const total = + // sumWalletBalances + + // (olasDepositBalance ?? 0) + + // (olasBondBalance ?? 0) + + // (optimisticRewardsEarnedForEpoch ?? 0) + + // (accruedServiceStakingRewards ?? 0); + + // return total; + // }, [accruedServiceStakingRewards, isLoaded, optimisticRewardsEarnedForEpoch]); + + // const totalOlasStakedBalance: number | undefined = useMemo(() => { + // if (!isLoaded) return; + // return (olasBondBalance ?? 0) + (olasDepositBalance ?? 0); + // }, [isLoaded, olasBondBalance, olasDepositBalance]); - setWalletBalances(walletBalances); + const updateBalances = useCallback(async (): Promise => { + if (!wallets) return; + + const walletBalances = await getCrossChainWalletBalances(wallets); + setWalletBalances(walletBalances); + try { // TODO: refactor to use ChainId enum, service from useService(), const serviceId = services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data .token; - if (!isNumber(serviceId)) { - setIsLoaded(true); - setIsBalanceLoaded(true); - return; - } - if ( !isNil(masterSafeAddress) && isAddress(masterSafeAddress) && @@ -224,39 +179,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { message.error('Unable to retrieve wallet balances'); setIsBalanceLoaded(true); } - }, [masterEoaAddress, masterSafeAddress, services]); - - const agentEoaAddress = useMemo( - () => - services?.[0]?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data - ?.instances?.[0], - [services], - ); - - const masterEoaBalance = useMemo( - () => masterEoaAddress && walletBalances[masterEoaAddress], - [masterEoaAddress, walletBalances], - ); - - const masterSafeBalance = useMemo( - () => masterSafeAddress && walletBalances[masterSafeAddress], - [masterSafeAddress, walletBalances], - ); - - const agentSafeBalance = useMemo( - () => - services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data - ?.multisig && - walletBalances[ - services[0].chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data - .multisig! - ], - [services, walletBalances], - ); - const agentEoaBalance = useMemo( - () => agentEoaAddress && walletBalances[agentEoaAddress], - [agentEoaAddress, walletBalances], - ); + }, [serviceAddresses, services, wallets]); const isLowBalance = useMemo(() => { if (!masterSafeBalance || !agentSafeBalance) return false; @@ -284,21 +207,12 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { isBalanceLoaded, olasBondBalance, olasDepositBalance, - masterEoaBalance, - masterSafeBalance, - totalEthBalance, - totalOlasBalance, isLowBalance, wallets, walletBalances, - agentSafeBalance, - agentEoaBalance, updateBalances, setIsPaused, totalOlasStakedBalance, - baseBalance, - ethereumBalance, - optimismBalance, }} > {children} @@ -306,84 +220,126 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { ); }; -export const getEthBalances = async ( - walletAddresses: Address[], -): Promise => { - const rpcIsValid = await EthersService.checkRpc( - `${process.env.OPTIMISM_RPC}`, - ); - if (!rpcIsValid) return; - - const ethBalances = await MulticallService.getEthBalances( - walletAddresses, - ).catch((e) => { - console.error(e); - return walletAddresses.reduce((acc, address) => { - acc[address] = 0; - return acc; - }, {} as AddressNumberRecord); - }); - - return ethBalances; +type BalanceResult = { + walletAddress: Address; + chainId: ChainId; + symbol: TokenSymbol; + isNative: boolean; + balance: BigNumberish; }; -export const getOlasBalances = async ( - walletAddresses: Address[], -): Promise => { - const rpcIsValid = await EthersService.checkRpc( - `${process.env.OPTIMISM_RPC}`, - ); - if (!rpcIsValid) return; - - const olasBalances = await MulticallService.getErc20Balances( - walletAddresses, - TOKEN_CONFIG[CHAIN_CONFIG.OPTIMISM.chainId].OLAS.address, +const getCrossChainWalletBalances = async ( + wallets: Wallets, +): Promise => { + const providerEntries = Object.entries(PROVIDERS); + + // Get balances for each chain + const balanceResults = await Promise.allSettled( + providerEntries.map( + async ([chainIdKey, { multicallProvider: chainMulticallProvider }]) => { + const chainId = +chainIdKey as ChainId; + + // Get tokens for this chain + const tokens = TOKEN_CONFIG[chainId]; + if (!tokens) return [] as BalanceResult[]; + + // Create balance checking promises for all tokens and wallets + const chainBalancePromises: Promise[] = Object.entries( + tokens, + ).map(async ([symbolKey, tokenConfig]) => { + const symbol = symbolKey as TokenSymbol; + + const results: BalanceResult[] = []; + const isNative = tokenConfig.tokenType === TokenType.NativeGas; + const isErc20 = tokenConfig.tokenType === TokenType.Erc20; + + // Filter relevant wallets + const relevantWallets = wallets.filter((wallet) => { + const isEoa = wallet.type === WalletType.EOA; + const isSafe = wallet.type === WalletType.Safe; + const isOnSameChain = isEoa || wallet.chainId === chainId; + return isEoa || (isSafe && isOnSameChain); + }); + + if (isNative) { + // Handle native token balances + const nativeBalances = await Promise.all( + relevantWallets.map(async (wallet) => { + const balance = await chainMulticallProvider.getEthBalance( + wallet.address, + ); + return { + walletAddress: wallet.address, + chainId, + symbol, + isNative: true, + balance, + } as BalanceResult; + }), + ); + results.push(...nativeBalances); + } + + if (isErc20) { + // Create ERC20 contract interface for multicall + const erc20Contract = new MulticallContract( + tokenConfig.address, + ERC20_BALANCE_OF_STRING_FRAGMENT, + ); + + // Prepare multicall for ERC20 balances + const erc20Calls = relevantWallets.map((wallet) => + erc20Contract.balanceOf(wallet.address), + ); + + // Execute multicall + const erc20Balances = await chainMulticallProvider.all(erc20Calls); + + // Map results to balance objects + const erc20Results = relevantWallets.map((wallet, index) => ({ + walletAddress: wallet.address, + chainId, + symbol, + isNative: false, + balance: erc20Balances[index], + })) as BalanceResult[]; + + results.push(...erc20Results); + } + + return results; + }); + + // Wait for all token balance promises to resolve and handle results + const chainResults = await Promise.allSettled(chainBalancePromises); + + // Filter and flatten successful results + return chainResults + .filter( + (result): result is PromiseFulfilledResult => + result.status === 'fulfilled', + ) + .map((result) => result.value) + .flat(); + }, + ), ); - return olasBalances; + // Filter and flatten successful results from all chains + return balanceResults + .filter( + (result): result is PromiseFulfilledResult => + result.status === 'fulfilled', + ) + .map((result) => result.value) + .flat(); }; -export const getWalletAddresses = ( - wallets: MiddlewareWalletResponse[], - serviceAddresses: Address[], -): Address[] => { - const walletsToCheck: Address[] = []; +// TODO: implement staked balances cross-chain for all master safes - for (const wallet of wallets) { - const { address } = wallet; - - if (address && isAddress(address)) { - walletsToCheck.push(address); - } - } - - for (const serviceAddress of serviceAddresses) { - if (serviceAddress && isAddress(`${serviceAddress}`)) { - walletsToCheck.push(serviceAddress); - } - } - - return walletsToCheck; -}; - -export const getWalletBalances = async ( - walletAddresses: Address[], -): Promise => { - const [ethBalances, olasBalances] = await Promise.all([ - getEthBalances(walletAddresses), - getOlasBalances(walletAddresses), - ]); - - if (!ethBalances) return; - if (!olasBalances) return; - - const tempWalletBalances: WalletAddressNumberRecord = {}; - for (const [address, balance] of Object.entries(ethBalances)) { - tempWalletBalances[address as Address] = { - [TokenSymbol.ETH]: balance, - [TokenSymbol.OLAS]: olasBalances[address as Address], - }; - } - - return tempWalletBalances; -}; +// const getCrossChainStakedBalances = async ( +// wallets: MasterSafe[], +// ): Promise<{ +// olasBondBalance?: number; +// olasDepositBalance?: number; +// }>[] => ({}); From 33ee2bca08062838dfda4a83ff6f1ac125575143 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 00:02:21 +0000 Subject: [PATCH 238/463] refactor: remove unused imports and clean up balance provider logic --- frontend/context/BalanceProvider.tsx | 37 +++++++++++----------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 4785bd391..bc4c4a7d6 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -11,7 +11,6 @@ import { SetStateAction, useCallback, useContext, - useMemo, useState, } from 'react'; import { useInterval } from 'usehooks-ts'; @@ -21,10 +20,6 @@ import { CHAIN_CONFIG } from '@/config/chains'; import { TOKEN_CONFIG, TokenType } from '@/config/tokens'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { PROVIDERS } from '@/constants/providers'; -import { - LOW_AGENT_SAFE_BALANCE, - LOW_MASTER_SAFE_BALANCE, -} from '@/constants/thresholds'; import { ChainId } from '@/enums/Chain'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { TokenSymbol } from '@/enums/Token'; @@ -87,7 +82,8 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { const [walletBalances, setWalletBalances] = useState([]); - // // TODO: refactor to support multiple chains, and gas tokens from config + // // TODO: refactor to parse `walletbalances` + // const totalEthBalance: number | undefined = useMemo(() => { // if (!isLoaded) return; // return Object.values(walletBalances).reduce( @@ -179,18 +175,19 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { message.error('Unable to retrieve wallet balances'); setIsBalanceLoaded(true); } - }, [serviceAddresses, services, wallets]); - - const isLowBalance = useMemo(() => { - if (!masterSafeBalance || !agentSafeBalance) return false; - if ( - masterSafeBalance.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; - }, [masterSafeBalance, agentSafeBalance]); + }, [services, wallets]); + + // TODO: include in walletBalances + // const isLowBalance = useMemo(() => { + // if (!masterSafeBalance || !agentSafeBalance) return false; + // if ( + // masterSafeBalance.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; + // }, [masterSafeBalance, agentSafeBalance]); useInterval( () => { @@ -205,14 +202,10 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { isLoaded, setIsLoaded, isBalanceLoaded, - olasBondBalance, - olasDepositBalance, - isLowBalance, wallets, walletBalances, updateBalances, setIsPaused, - totalOlasStakedBalance, }} > {children} From a48ced30cffa6fec79fcd69b29c876a72606d4da Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 12:04:29 +0000 Subject: [PATCH 239/463] refactor: move crosschain staked logic --- frontend/context/BalanceProvider.tsx | 72 ++++++++++++++++++++++++---- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index bc4c4a7d6..241bf428f 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -110,10 +110,10 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { // return total; // }, [accruedServiceStakingRewards, isLoaded, optimisticRewardsEarnedForEpoch]); - // const totalOlasStakedBalance: number | undefined = useMemo(() => { - // if (!isLoaded) return; - // return (olasBondBalance ?? 0) + (olasDepositBalance ?? 0); - // }, [isLoaded, olasBondBalance, olasDepositBalance]); + const totalOlasStakedBalance: number | undefined = useMemo(() => { + if (!isLoaded) return; + return (olasBondBalance ?? 0) + (olasDepositBalance ?? 0); + }, [isLoaded]); const updateBalances = useCallback(async (): Promise => { if (!wallets) return; @@ -330,9 +330,61 @@ const getCrossChainWalletBalances = async ( // TODO: implement staked balances cross-chain for all master safes -// const getCrossChainStakedBalances = async ( -// wallets: MasterSafe[], -// ): Promise<{ -// olasBondBalance?: number; -// olasDepositBalance?: number; -// }>[] => ({}); +const getCrossChainStakedBalances = async ( + services: MiddlewareServiceResponse[], + wallets: MasterSafe[], +): Promise< + { + address: `0x${string}`; + olasBondBalance?: number; + olasDepositBalance?: number; + }[] +> => { + const serviceId = + services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data + .token; + + if ( + !isNil(masterSafeAddress) && + isAddress(masterSafeAddress) && + serviceId > 0 + ) { + const { depositValue, bondValue, serviceState } = + await StakedAgentService.getServiceRegistryInfo( + masterSafeAddress, + serviceId, + ChainId.Gnosis, // TODO: refactor to get chain id from service + ); + + switch (serviceState) { + case ServiceRegistryL2ServiceState.NonExistent: + setOlasBondBalance(0); + setOlasDepositBalance(0); + break; + case ServiceRegistryL2ServiceState.PreRegistration: + setOlasBondBalance(0); + setOlasDepositBalance(0); + break; + case ServiceRegistryL2ServiceState.ActiveRegistration: + setOlasBondBalance(0); + setOlasDepositBalance(depositValue); + break; + case ServiceRegistryL2ServiceState.FinishedRegistration: + setOlasBondBalance(bondValue); + setOlasDepositBalance(depositValue); + break; + case ServiceRegistryL2ServiceState.Deployed: + setOlasBondBalance(bondValue); + setOlasDepositBalance(depositValue); + break; + case ServiceRegistryL2ServiceState.TerminatedBonded: + setOlasBondBalance(bondValue); + setOlasDepositBalance(0); + break; + } + } + + // update balance loaded state + setIsLoaded(true); + setIsBalanceLoaded(true); +}; From 7ef51752eba1c719a78b9dce5e44498c49578671 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 21:58:59 +0000 Subject: [PATCH 240/463] refactor: update wallet owner type and clean up imports in ServicesProvider --- frontend/context/ServicesProvider.tsx | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index d0ff72dc2..392d6cfaa 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -14,12 +14,7 @@ import { MiddlewareServiceResponse } from '@/client'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { ChainId } from '@/enums/Chain'; -import { - AgentEoa, - AgentWallets, - WalletOwner, - WalletType, -} from '@/enums/Wallet'; +import { AgentWallets, WalletOwnerType, WalletType } from '@/enums/Wallet'; import { UsePause, usePause } from '@/hooks/usePause'; import { ServicesService } from '@/service/Services'; import { Service } from '@/types/Service'; @@ -116,14 +111,11 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { if (instances) { acc.push( - ...instances.map( - (instance: string) => - ({ - address: instance, - type: WalletType.EOA, - owner: WalletOwner.Agent, - }), - ), + ...instances.map((instance: string) => ({ + address: instance, + type: WalletType.EOA, + owner: WalletOwnerType.Agent, + })), ); } @@ -131,7 +123,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { acc.push({ address: multisig, type: WalletType.Safe, - owner: WalletOwner.Agent, + owner: WalletOwnerType.Agent, chainId, }); } From a307edbed137f4cbb2548104b7204443af2016e5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 21:59:17 +0000 Subject: [PATCH 241/463] refactor: update wallet owner to use WalletOwnerType in WalletProvider --- frontend/context/WalletProvider.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/context/WalletProvider.tsx b/frontend/context/WalletProvider.tsx index 4ae8beb43..f09260680 100644 --- a/frontend/context/WalletProvider.tsx +++ b/frontend/context/WalletProvider.tsx @@ -8,7 +8,7 @@ import { MasterEoa, MasterSafe, MasterWallets, - WalletOwner, + WalletOwnerType, WalletType, } from '@/enums/Wallet'; import { UsePause } from '@/hooks/usePause'; @@ -34,7 +34,7 @@ const transformMiddlewareWalletResponse = ( ): MasterWallets => { const masterEoa: MasterEoa = { address: data.address, - owner: WalletOwner.Master, + owner: WalletOwnerType.Master, type: WalletType.EOA, }; @@ -42,7 +42,7 @@ const transformMiddlewareWalletResponse = ( ([middlewareChain, address]) => ({ address, chainId: convertMiddlewareChainToChainId(+middlewareChain), - owner: WalletOwner.Master, + owner: WalletOwnerType.Master, type: WalletType.Safe, }), ); From 60903dfdeb3347905978181fdbbb645fc8b2b6b5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 21:59:22 +0000 Subject: [PATCH 242/463] refactor: rename WalletOwner enum to WalletOwnerType and update references --- frontend/enums/Wallet.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts index 2db21b9f8..f0498180e 100644 --- a/frontend/enums/Wallet.ts +++ b/frontend/enums/Wallet.ts @@ -6,7 +6,7 @@ export enum WalletType { Safe = 'multisig', EOA = 'eoa', } -export enum WalletOwner { +export enum WalletOwnerType { Master = 'master', // user Agent = 'agent', } @@ -14,7 +14,7 @@ export enum WalletOwner { export type MasterEoa = { address: Address; type: WalletType.EOA; - owner: WalletOwner; + owner: WalletOwnerType.Master; }; export type MasterSafe = Omit & { @@ -27,7 +27,7 @@ export type MasterWallet = MasterEoa | MasterSafe; export type AgentEoa = { address: Address; type: WalletType.EOA; - owner: WalletOwner.Agent; + owner: WalletOwnerType.Agent; }; export type AgentSafe = Omit & { From 645fa27de208b45dc04ed459b0019ccff3312092 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 23:14:51 +0000 Subject: [PATCH 243/463] chore: lint fix serviceTemplates --- frontend/constants/serviceTemplates.ts | 70 +++++++++++++------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 1204df060..8a781f0e9 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -1,4 +1,4 @@ -import { ServiceTemplate, EnvProvisionType } from '@/client'; +import { EnvProvisionType, ServiceTemplate } from '@/client'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; @@ -31,10 +31,10 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ }, env_variables: { GNOSIS_LEDGER_RPC: { - name: "Gnosis ledger RPC", - description: "", - value: "", - provision_type: EnvProvisionType.COMPUTED + name: 'Gnosis ledger RPC', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, }, // ETHEREUM_LEDGER_RPC: { // name: "Ethereum ledger RPC", @@ -53,49 +53,49 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ // description: "", // value: "", // provision_type: EnvProvisionType.COMPUTED - // }, + // }, STAKING_CONTRACT_ADDRESS: { - name: "Staking contract address", - description: "", - value: "", - provision_type: EnvProvisionType.COMPUTED + name: 'Staking contract address', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, }, MECH_ACTIVITY_CHECKER_CONTRACT: { - name: "Mech activity checker contract", - description: "", - value: "", - provision_type: EnvProvisionType.COMPUTED + name: 'Mech activity checker contract', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, }, MECH_CONTRACT_ADDRESS: { - name: "Mech contract address", - description: "", - value: "", - provision_type: EnvProvisionType.COMPUTED + name: 'Mech contract address', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, }, MECH_REQUEST_PRICE: { - name: "Mech request price", - description: "", - value: "", - provision_type: EnvProvisionType.COMPUTED + name: 'Mech request price', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, }, USE_MECH_MARKETPLACE: { - name: "Use Mech marketplace", - description: "", - value: "", - provision_type: EnvProvisionType.COMPUTED + name: 'Use Mech marketplace', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, }, REQUESTER_STAKING_INSTANCE_ADDRESS: { - name: "Requester staking instance address", - description: "", - value: "", - provision_type: EnvProvisionType.COMPUTED + name: 'Requester staking instance address', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, }, PRIORITY_MECH_ADDRESS: { - name: "Priority Mech address", - description: "", - value: "", - provision_type: EnvProvisionType.COMPUTED - } + name: 'Priority Mech address', + description: '', + value: '', + provision_type: EnvProvisionType.COMPUTED, + }, }, }, // { From 1e5134ec72c6bc5c122fc3169b995ca62afbaf1b Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 23:15:07 +0000 Subject: [PATCH 244/463] feat: add response type for GetServiceRegistryInfo --- frontend/service/agents/StakedAgentService.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/service/agents/StakedAgentService.ts b/frontend/service/agents/StakedAgentService.ts index a10a34cfc..f6e0c7981 100644 --- a/frontend/service/agents/StakedAgentService.ts +++ b/frontend/service/agents/StakedAgentService.ts @@ -21,6 +21,12 @@ import { Address } from '@/types/Address'; export const ONE_YEAR = 1 * 24 * 60 * 60 * 365; +export type GetServiceRegistryInfoResponse = { + bondValue: number; + depositValue: number; + serviceState: ServiceRegistryL2ServiceState; +}; + /** * */ @@ -89,11 +95,7 @@ export abstract class StakedAgentService { address: Address, // generally masterSafeAddress serviceId: number, chainId: ChainId, - ): Promise<{ - bondValue: number; - depositValue: number; - serviceState: ServiceRegistryL2ServiceState; - }> => { + ): Promise => { if (!OLAS_CONTRACTS[chainId]) { throw new Error('Chain not supported'); } From 30d83e87905c94db9c96de4486528c5507d7a0c5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Tue, 19 Nov 2024 23:15:25 +0000 Subject: [PATCH 245/463] feat: wallet balances, and staked balances, cross-chain --- frontend/context/BalanceProvider.tsx | 340 +++++++++++++-------------- 1 file changed, 170 insertions(+), 170 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 241bf428f..d32476561 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -1,9 +1,5 @@ -import { message } from 'antd'; import { BigNumberish } from 'ethers'; -import { isAddress } from 'ethers/lib/utils'; import { Contract as MulticallContract } from 'ethers-multicall'; -import { isNil } from 'lodash'; -import { ValueOf } from 'next/dist/shared/lib/constants'; import { createContext, Dispatch, @@ -11,23 +7,24 @@ import { SetStateAction, useCallback, useContext, + useEffect, useState, } from 'react'; -import { useInterval } from 'usehooks-ts'; import { ERC20_BALANCE_OF_STRING_FRAGMENT } from '@/abis/erc20'; -import { CHAIN_CONFIG } from '@/config/chains'; +import { MiddlewareServiceResponse } from '@/client'; import { TOKEN_CONFIG, TokenType } from '@/config/tokens'; -import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { PROVIDERS } from '@/constants/providers'; import { ChainId } from '@/enums/Chain'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { TokenSymbol } from '@/enums/Token'; import { Wallets, WalletType } from '@/enums/Wallet'; import { useServices } from '@/hooks/useServices'; -import { StakedAgentService } from '@/service/agents/StakedAgentService'; +import { + GetServiceRegistryInfoResponse, + StakedAgentService, +} from '@/service/agents/StakedAgentService'; import { Address } from '@/types/Address'; -import { WalletAddressNumberRecord } from '@/types/Records'; import { OnlineStatusContext } from './OnlineStatusProvider'; import { WalletContext } from './WalletProvider'; @@ -35,52 +32,53 @@ import { WalletContext } from './WalletProvider'; export const BalanceContext = createContext<{ isLoaded: boolean; setIsLoaded: Dispatch>; - isBalanceLoaded: boolean; - olasBondBalance?: number; - olasDepositBalance?: number; - masterEoaBalance?: ValueOf; - masterSafeBalance?: ValueOf; - totalEthBalance?: number; totalOlasBalance?: number; isLowBalance: boolean; - wallets?: Wallets[]; - walletBalances: WalletAddressNumberRecord; - agentSafeBalance?: ValueOf; - agentEoaBalance?: ValueOf; updateBalances: () => Promise; setIsPaused: Dispatch>; - totalOlasStakedBalance?: number; + walletBalances: BalanceResult[]; + stakedBalances: CrossChainStakedBalances; }>({ isLoaded: false, setIsLoaded: () => {}, - isBalanceLoaded: false, - olasBondBalance: undefined, - olasDepositBalance: undefined, - totalEthBalance: undefined, totalOlasBalance: undefined, isLowBalance: false, - wallets: undefined, - walletBalances: {}, - agentSafeBalance: undefined, - agentEoaBalance: undefined, updateBalances: async () => {}, setIsPaused: () => {}, - totalOlasStakedBalance: undefined, + walletBalances: [], + stakedBalances: {}, }); export const BalanceProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); const { wallets } = useContext(WalletContext); - const { services, serviceAddresses } = useServices(); + const { services } = useServices(); // const { optimisticRewardsEarnedForEpoch, accruedServiceStakingRewards } = // useContext(RewardContext); const [isLoaded, setIsLoaded] = useState(false); const [isPaused, setIsPaused] = useState(false); - const [isBalanceLoaded, setIsBalanceLoaded] = useState(false); - const [walletBalances, setWalletBalances] = useState([]); + const [stakedBalances, setStakedBalances] = + useState(); + + const updateBalances = useCallback(async () => { + if (wallets && services) { + getCrossChainWalletBalances(wallets).then((balances) => { + setWalletBalances(balances); + setIsLoaded(true); + }); + + getCrossChainStakedBalances(services).then((balances) => { + setStakedBalances(balances); + }); + } + }, [services, wallets]); + + useEffect(() => { + if (!isLoaded) updateBalances(); + }, [isLoaded, updateBalances]); // // TODO: refactor to parse `walletbalances` @@ -110,102 +108,40 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { // return total; // }, [accruedServiceStakingRewards, isLoaded, optimisticRewardsEarnedForEpoch]); - const totalOlasStakedBalance: number | undefined = useMemo(() => { - if (!isLoaded) return; - return (olasBondBalance ?? 0) + (olasDepositBalance ?? 0); - }, [isLoaded]); - - const updateBalances = useCallback(async (): Promise => { - if (!wallets) return; - - const walletBalances = await getCrossChainWalletBalances(wallets); - setWalletBalances(walletBalances); - - try { - // TODO: refactor to use ChainId enum, service from useService(), - const serviceId = - services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data - .token; - - if ( - !isNil(masterSafeAddress) && - isAddress(masterSafeAddress) && - serviceId > 0 - ) { - const { depositValue, bondValue, serviceState } = - await StakedAgentService.getServiceRegistryInfo( - masterSafeAddress, - serviceId, - ChainId.Gnosis, // TODO: refactor to get chain id from service - ); - - switch (serviceState) { - case ServiceRegistryL2ServiceState.NonExistent: - setOlasBondBalance(0); - setOlasDepositBalance(0); - break; - case ServiceRegistryL2ServiceState.PreRegistration: - setOlasBondBalance(0); - setOlasDepositBalance(0); - break; - case ServiceRegistryL2ServiceState.ActiveRegistration: - setOlasBondBalance(0); - setOlasDepositBalance(depositValue); - break; - case ServiceRegistryL2ServiceState.FinishedRegistration: - setOlasBondBalance(bondValue); - setOlasDepositBalance(depositValue); - break; - case ServiceRegistryL2ServiceState.Deployed: - setOlasBondBalance(bondValue); - setOlasDepositBalance(depositValue); - break; - case ServiceRegistryL2ServiceState.TerminatedBonded: - setOlasBondBalance(bondValue); - setOlasDepositBalance(0); - break; - } - } - - // update balance loaded state - setIsLoaded(true); - setIsBalanceLoaded(true); - } catch (error) { - console.error(error); - message.error('Unable to retrieve wallet balances'); - setIsBalanceLoaded(true); - } - }, [services, wallets]); - - // TODO: include in walletBalances - // const isLowBalance = useMemo(() => { - // if (!masterSafeBalance || !agentSafeBalance) return false; - // if ( - // masterSafeBalance.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; - // }, [masterSafeBalance, agentSafeBalance]); - - useInterval( - () => { - updateBalances(); - }, - isPaused || !isOnline ? null : FIVE_SECONDS_INTERVAL, - ); + // const totalOlasStakedBalance: number | undefined = useMemo(() => { + // if (!isLoaded) return; + // return (olasBondBalance ?? 0) + (olasDepositBalance ?? 0); + // }, [isLoaded]); + + // // TODO: include in walletBalances + // // const isLowBalance = useMemo(() => { + // // if (!masterSafeBalance || !agentSafeBalance) return false; + // // if ( + // // masterSafeBalance.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; + // // }, [masterSafeBalance, agentSafeBalance]); + + // useInterval( + // () => { + // updateBalances(); + // }, + // isPaused || !isOnline ? null : FIVE_SECONDS_INTERVAL, + // ); return ( {children} @@ -330,61 +266,125 @@ const getCrossChainWalletBalances = async ( // TODO: implement staked balances cross-chain for all master safes +type CrossChainStakedBalances = { + [serviceId: string]: { + [chainId: number]: { + olasBondBalance: number; + olasDepositBalance: number; + }; + }; +}; + const getCrossChainStakedBalances = async ( services: MiddlewareServiceResponse[], - wallets: MasterSafe[], -): Promise< - { - address: `0x${string}`; - olasBondBalance?: number; - olasDepositBalance?: number; - }[] -> => { - const serviceId = - services?.[0]?.chain_configs[CHAIN_CONFIG.OPTIMISM.chainId].chain_data - .token; - - if ( - !isNil(masterSafeAddress) && - isAddress(masterSafeAddress) && - serviceId > 0 - ) { - const { depositValue, bondValue, serviceState } = - await StakedAgentService.getServiceRegistryInfo( - masterSafeAddress, - serviceId, - ChainId.Gnosis, // TODO: refactor to get chain id from service +): Promise => { + const result: CrossChainStakedBalances = {}; + + // for each service, create a nest objects for chain staked balances + const registryInfoCalls: Promise[] = []; + services.forEach((service) => { + const homeChainId = service.home_chain_id; + const homeChainConfig = service.chain_configs[homeChainId]; + const { multisig, token } = homeChainConfig.chain_data; + + if (!multisig || !token) { + registryInfoCalls.push( + Promise.resolve({ + depositValue: 0, + bondValue: 0, + serviceState: ServiceRegistryL2ServiceState.NonExistent, + }), ); + return; + } - switch (serviceState) { - case ServiceRegistryL2ServiceState.NonExistent: - setOlasBondBalance(0); - setOlasDepositBalance(0); - break; - case ServiceRegistryL2ServiceState.PreRegistration: - setOlasBondBalance(0); - setOlasDepositBalance(0); - break; - case ServiceRegistryL2ServiceState.ActiveRegistration: - setOlasBondBalance(0); - setOlasDepositBalance(depositValue); - break; - case ServiceRegistryL2ServiceState.FinishedRegistration: - setOlasBondBalance(bondValue); - setOlasDepositBalance(depositValue); - break; - case ServiceRegistryL2ServiceState.Deployed: - setOlasBondBalance(bondValue); - setOlasDepositBalance(depositValue); - break; - case ServiceRegistryL2ServiceState.TerminatedBonded: - setOlasBondBalance(bondValue); - setOlasDepositBalance(0); - break; + registryInfoCalls.push( + StakedAgentService.getServiceRegistryInfo(multisig, token, homeChainId), + ); + }); + + // TODO: chunk and batch multicalls by chain, + // currently Promise is returned by `StakedAgentService.getServiceRegistryInfo` + // will not scale well with large number of services + const registryInfos = await Promise.allSettled(registryInfoCalls); + + registryInfos.forEach((res, index) => { + if (res.status === 'fulfilled') { + const { depositValue, bondValue, serviceState } = + res.value as GetServiceRegistryInfoResponse; + const serviceId = services[index].service_config_id; + const homeChainId = services[index].home_chain_id; + + if (!result[serviceId]) result[serviceId] = {}; + if (!result[serviceId][homeChainId]) + result[serviceId][homeChainId] = { + olasBondBalance: 0, + olasDepositBalance: 0, + }; + + // service state is used to determine the correct bond and deposit balances + // stops funds from being displayed incorrectly during service state transitions + const serviceStateBondDepositBalances = correctBondDepositByServiceState({ + olasBondBalance: bondValue, + olasDepositBalance: depositValue, + serviceState, + }); + + result[serviceId][homeChainId] = serviceStateBondDepositBalances; } - } + }); + + return result; +}; - // update balance loaded state - setIsLoaded(true); - setIsBalanceLoaded(true); +/** + * Corrects the bond and deposit balances based on the service state + * @note the service state is used to determine the correct bond and deposit balances + */ +const correctBondDepositByServiceState = ({ + olasBondBalance, + olasDepositBalance, + serviceState, +}: { + olasBondBalance: number; + olasDepositBalance: number; + serviceState: ServiceRegistryL2ServiceState; +}): { + olasBondBalance: number; + olasDepositBalance: number; +} => { + switch (serviceState) { + case ServiceRegistryL2ServiceState.NonExistent: + return { + olasBondBalance: 0, + olasDepositBalance: 0, + }; + case ServiceRegistryL2ServiceState.PreRegistration: + return { + olasBondBalance: 0, + olasDepositBalance: 0, + }; + case ServiceRegistryL2ServiceState.ActiveRegistration: + return { + olasBondBalance: 0, + olasDepositBalance, + }; + case ServiceRegistryL2ServiceState.FinishedRegistration: + return { + olasBondBalance, + olasDepositBalance, + }; + case ServiceRegistryL2ServiceState.Deployed: + return { + olasBondBalance, + olasDepositBalance, + }; + case ServiceRegistryL2ServiceState.TerminatedBonded: + return { + olasBondBalance, + olasDepositBalance: 0, + }; + default: + throw new Error('Invalid service state'); + } }; From 20b39b057eb9e6d25acf57d6474727fa6bb4492d Mon Sep 17 00:00:00 2001 From: Mohan Date: Wed, 20 Nov 2024 15:44:59 +0530 Subject: [PATCH 246/463] feat: multi staking support (part-1) (#463) * feat: rename StakingProgramProvider to StakingProgramsProvider and update related hooks for multiple staking programs * feat: update StakingProgramProvider references to StakingProgramsProvider across components and hooks * feat: add AgentTypeProvider context for managing agent type state * feat: add selectedAgentConfig and updateAgentType to ServicesProvider context * feat: update AGENT_CONFIG structure and add AgentConfig type for improved agent management * feat: refactor StakingContractDetailsProvider and StakingProgramsProvider to utilize serviceId and improve query handling * feat: remove unused hooks and refactor useServiceId to utilize selectedAgentConfig for improved agent handling * feat: remove AgentTypeProvider context as part of agent management refactor * feat: rename StakingProgramsProvider to StakingProgramProvider for consistency and improve type handling * feat: rename StakingProgramsProvider to StakingProgramProvider and update related hooks for consistency * feat: rename StakingProgramsContext to StakingProgramContext for consistency across providers and hooks * feat: rename isActiveStakingProgramsLoaded to isActiveStakingProgramLoaded for consistency --- .../AgentButton/AgentNotRunningButton.tsx | 11 ++- .../StakingRewardsThisEpoch.tsx | 6 +- frontend/config/agents.ts | 12 +++- frontend/context/ServicesProvider.tsx | 28 ++++++++ .../StakingContractDetailsProvider.tsx | 68 +++++++++++++------ frontend/context/StakingProgramProvider.tsx | 42 ++++++------ frontend/enums/Agent.ts | 2 +- frontend/hooks/useAgent.ts | 3 - frontend/hooks/useChainId.ts | 3 - frontend/hooks/useRewardsHistory.ts | 20 +++--- frontend/hooks/useService.ts | 11 +-- frontend/hooks/useStakingContractDetails.ts | 42 +----------- frontend/hooks/useStakingProgram.ts | 58 +++++++++++++--- frontend/service/agents/PredictTrader.ts | 5 +- frontend/service/agents/StakedAgentService.ts | 36 +++++++--- frontend/types/Agent.ts | 12 ++++ 16 files changed, 228 insertions(+), 131 deletions(-) delete mode 100644 frontend/hooks/useAgent.ts delete mode 100644 frontend/hooks/useChainId.ts create mode 100644 frontend/types/Agent.ts diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index 01a749a9e..fc4fc0bac 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -3,7 +3,6 @@ import { useCallback, useMemo } from 'react'; import { MiddlewareChain, MiddlewareDeploymentStatus } from '@/client'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; -import { DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useBalance } from '@/hooks/useBalance'; @@ -57,14 +56,13 @@ export const AgentNotRunningButton = () => { refetchActiveStakingContractDetails, } = useStakingContractContext(); - const { activeStakingProgramId, defaultStakingProgramId } = - useStakingProgram(); + const { activeStakingProgramId } = useStakingProgram(); const { isEligibleForStaking, isAgentEvicted, isServiceStaked } = useActiveStakingContractInfo(); const { hasEnoughServiceSlots } = useStakingContractDetails( - activeStakingProgramId ?? defaultStakingProgramId, + activeStakingProgramId, ); // const minStakingDeposit = @@ -97,8 +95,7 @@ export const AgentNotRunningButton = () => { setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYING); // Get the active staking program id; default id if there's no agent yet - const stakingProgramId: StakingProgramId = - activeStakingProgramId ?? DEFAULT_STAKING_PROGRAM_ID; + const stakingProgramId: StakingProgramId = activeStakingProgramId; // Create master safe if it doesn't exist try { @@ -118,7 +115,7 @@ export const AgentNotRunningButton = () => { // Then create / deploy the service try { await ServicesService.createService({ - stakingProgramId, + activeStakingProgramId, serviceTemplate, deploy: true, useMechMarketplace: false, diff --git a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx index c6796dcfa..17540829c 100644 --- a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx @@ -5,15 +5,17 @@ import { Popover, Typography } from 'antd'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { POPOVER_WIDTH_MEDIUM } from '@/constants/width'; import { getLatestEpochDetails } from '@/graphql/queries'; -import { useChainId } from '@/hooks/useChainId'; +import { useServices } from '@/hooks/useServices'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { formatToTime } from '@/utils/time'; const { Text } = Typography; const useEpochEndTime = () => { + const { selectedAgentConfig } = useServices(); + const chainId = selectedAgentConfig.homeChainId; + const { activeStakingProgramAddress } = useStakingProgram(); - const chainId = useChainId(); const { data, isLoading } = useQuery({ queryKey: REACT_QUERY_KEYS.LATEST_EPOCH_TIME_KEY( diff --git a/frontend/config/agents.ts b/frontend/config/agents.ts index db97cbf2c..26ed492d7 100644 --- a/frontend/config/agents.ts +++ b/frontend/config/agents.ts @@ -1,11 +1,15 @@ import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; import { PredictTraderService } from '@/service/agents/PredictTrader'; +// import { OptimusService } from '@/service/agents/Optimus'; +import { AgentConfig } from '@/types/Agent'; // TODO: complete this config // TODO: add funding requirements -export const AGENT_CONFIG = { +export const AGENT_CONFIG: { + [key in AgentType]: AgentConfig; +} = { [AgentType.PredictTrader]: { name: 'Predict Trader', homeChainId: ChainId.Gnosis, @@ -16,11 +20,17 @@ export const AGENT_CONFIG = { requiresMasterSafesOn: [ChainId.Gnosis], serviceApi: PredictTraderService, }, + // TODO: check optimus config // [AgentType.Optimus]: { // name: 'Optimus', // homeChainId: ChainId.Optimism, // requiresAgentSafesOn: [ChainId.Optimism, ChainId.Ethereum, ChainId.Base], // requiresMasterSafesOn: [ChainId.Optimism, ChainId.Ethereum, ChainId.Base], + // agentSafeFundingRequirements: { + // [ChainId.Optimism]: 100000000000000000, + // [ChainId.Ethereum]: 100000000000000000, + // [ChainId.Base]: 100000000000000000, + // }, // serviceApi: OptimusService, // }, }; diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 2a79934ec..8ee052cda 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -11,13 +11,17 @@ import { } from 'react'; import { MiddlewareServiceResponse } from '@/client'; +import { AGENT_CONFIG } from '@/config/agents'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; import { AgentWallets, WalletOwner, WalletType } from '@/enums/Wallet'; import { UsePause, usePause } from '@/hooks/usePause'; import { ServicesService } from '@/service/Services'; +import { AgentConfig } from '@/types/Agent'; import { Service } from '@/types/Service'; +import { Maybe } from '@/types/Util'; import { OnlineStatusContext } from './OnlineStatusProvider'; @@ -27,6 +31,8 @@ type ServicesContextType = { servicesByChain?: Record; selectService: (serviceUuid: string) => void; selectedService?: Service; + selectedAgentConfig: AgentConfig; + updateAgentType: (agentType: AgentType) => void; } & Partial> & UsePause; @@ -35,6 +41,8 @@ export const ServicesContext = createContext({ setPaused: noop, togglePaused: noop, selectService: noop, + selectedAgentConfig: AGENT_CONFIG[AgentType.PredictTrader], + updateAgentType: noop, }); /** @@ -44,6 +52,11 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); const { paused, setPaused, togglePaused } = usePause(); + // selected agent type + const [selectedAgentType, setAgentType] = useState( + AgentType.PredictTrader, + ); + // user selected service identifier const [selectedServiceConfigId, setSelectedServiceConfigId] = useState(); @@ -73,6 +86,19 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { setSelectedServiceConfigId(serviceUuid); }, []); + const updateAgentType = useCallback((agentType: AgentType) => { + setAgentType(agentType); + }, []); + + const selectedAgentConfig = useMemo(() => { + const config: Maybe = AGENT_CONFIG[selectedAgentType]; + + if (!config) { + throw new Error(`Agent config not found for ${selectedAgentType}`); + } + return config; + }, [selectedAgentType]); + const servicesByChain = useMemo(() => { if (!isFetched) return; if (!services) return; @@ -171,6 +197,8 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { togglePaused, selectService, selectedService, + selectedAgentConfig, + updateAgentType, }} > {children} diff --git a/frontend/context/StakingContractDetailsProvider.tsx b/frontend/context/StakingContractDetailsProvider.tsx index 8796e5daf..9b14e13d3 100644 --- a/frontend/context/StakingContractDetailsProvider.tsx +++ b/frontend/context/StakingContractDetailsProvider.tsx @@ -1,4 +1,5 @@ -import { useQueries } from '@tanstack/react-query'; +import { useQueries, useQuery } from '@tanstack/react-query'; +import { Maybe } from 'graphql/jsutils/Maybe'; import { createContext, Dispatch, @@ -9,36 +10,34 @@ import { useState, } from 'react'; +import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useAgent } from '@/hooks/useAgent'; -import { useChainId } from '@/hooks/useChainId'; -import { useStakingContractDetailsByStakingProgram } from '@/hooks/useStakingContractDetails'; +import { useServiceId } from '@/hooks/useService'; +import { useServices } from '@/hooks/useServices'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; import { StakingContractDetails } from '@/types/Autonolas'; -import { - INITIAL_DEFAULT_STAKING_PROGRAM_ID, - StakingProgramContext, -} from './StakingProgramProvider'; +import { StakingProgramContext } from './StakingProgramProvider'; /** * hook to get all staking contract details */ const useAllStakingContractDetails = () => { - const stakingPrograms = [INITIAL_DEFAULT_STAKING_PROGRAM_ID]; - const chainId = useChainId(); - const currentAgent = useAgent(); + const { allStakingProgramIds } = useStakingProgram(); + const { selectedAgentConfig } = useServices(); + const { serviceApi, homeChainId } = selectedAgentConfig; const queryResults = useQueries({ - queries: stakingPrograms.map((programId) => ({ + queries: allStakingProgramIds.map((programId) => ({ queryKey: REACT_QUERY_KEYS.ALL_STAKING_CONTRACT_DETAILS( - chainId, + homeChainId, programId, ), queryFn: async () => - await currentAgent.serviceApi.getStakingContractDetailsByName( - programId, - chainId, + await serviceApi.getStakingContractDetailsByName( + programId as StakingProgramId, + homeChainId, ), onError: (error: Error) => { console.error( @@ -50,7 +49,7 @@ const useAllStakingContractDetails = () => { }); // Aggregate results into a record - const allStakingContractDetailsRecord = stakingPrograms.reduce( + const allStakingContractDetailsRecord = allStakingProgramIds.reduce( (record, programId, index) => { const query = queryResults[index]; if (query.status === 'success') { @@ -70,8 +69,37 @@ const useAllStakingContractDetails = () => { return { allStakingContractDetailsRecord, isAllStakingContractDetailsLoaded }; }; +/** + * hook to get staking contract details by staking program + */ +const useStakingContractDetailsByStakingProgram = ( + serviceId: Maybe, + stakingProgramId: Maybe, + isPaused?: boolean, +) => { + const { selectedAgentConfig } = useServices(); + const { serviceApi, homeChainId: chainId } = selectedAgentConfig; + return useQuery({ + queryKey: REACT_QUERY_KEYS.STAKING_CONTRACT_DETAILS_BY_STAKING_PROGRAM_KEY( + chainId, + serviceId!, + stakingProgramId!, + ), + queryFn: async () => { + return await serviceApi.getStakingContractDetailsByServiceIdStakingProgram( + serviceId!, + stakingProgramId!, + chainId, + ); + }, + enabled: !!serviceId && !!stakingProgramId && !!chainId && !isPaused, + refetchInterval: !isPaused ? FIVE_SECONDS_INTERVAL : () => false, + refetchOnWindowFocus: false, + }); +}; + type StakingContractDetailsContextProps = { - activeStakingContractDetails?: Partial; + activeStakingContractDetails: Partial>; isActiveStakingContractDetailsLoaded: boolean; isPaused: boolean; allStakingContractDetailsRecord?: Record< @@ -88,7 +116,7 @@ type StakingContractDetailsContextProps = { */ export const StakingContractDetailsContext = createContext({ - activeStakingContractDetails: undefined, + activeStakingContractDetails: null, isPaused: false, isAllStakingContractDetailsRecordLoaded: false, isActiveStakingContractDetailsLoaded: false, @@ -104,6 +132,7 @@ export const StakingContractDetailsProvider = ({ children, }: PropsWithChildren) => { const [isPaused, setIsPaused] = useState(false); + const serviceId = useServiceId(); const { activeStakingProgramId } = useContext(StakingProgramContext); const { @@ -111,6 +140,7 @@ export const StakingContractDetailsProvider = ({ isLoading: isActiveStakingContractDetailsLoading, refetch: refetchActiveStakingContract, } = useStakingContractDetailsByStakingProgram( + serviceId, activeStakingProgramId, isPaused, ); diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index 684a2bd56..3e6685747 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -1,19 +1,19 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { Maybe } from 'graphql/jsutils/Maybe'; import { createContext, PropsWithChildren, useCallback } from 'react'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useAgent } from '@/hooks/useAgent'; -import { useChainId } from '@/hooks/useChainId'; import { useServiceId } from '@/hooks/useService'; +import { useServices } from '@/hooks/useServices'; import { Nullable } from '@/types/Util'; -export const INITIAL_DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.PearlBeta; +const INITIAL_DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.PearlBeta; export const StakingProgramContext = createContext<{ isActiveStakingProgramLoaded: boolean; - activeStakingProgramId?: Nullable; + activeStakingProgramId: Maybe; }>({ isActiveStakingProgramLoaded: false, activeStakingProgramId: null, @@ -24,55 +24,55 @@ export const StakingProgramContext = createContext<{ */ const useGetActiveStakingProgramId = () => { const queryClient = useQueryClient(); - const agent = useAgent(); - const chainId = useChainId(); + const { selectedAgentConfig } = useServices(); const serviceId = useServiceId(); + const { serviceApi, homeChainId } = selectedAgentConfig; + const response = useQuery({ - queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(chainId, serviceId!), + queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(homeChainId, serviceId!), queryFn: async () => { - const response = - await agent.serviceApi.getCurrentStakingProgramByServiceId( - serviceId!, - chainId, - ); - return response?.length === 0 - ? INITIAL_DEFAULT_STAKING_PROGRAM_ID - : response; + const response = await serviceApi.getCurrentStakingProgramByServiceId( + serviceId!, + homeChainId, + ); + return response || INITIAL_DEFAULT_STAKING_PROGRAM_ID; }, - enabled: !!chainId && !!serviceId, + enabled: !!homeChainId && !!serviceId, refetchInterval: serviceId ? FIVE_SECONDS_INTERVAL : false, }); const setActiveStakingProgramId = useCallback( (stakingProgramId: Nullable) => { if (!serviceId) return; + if (!stakingProgramId) return; + // update the active staking program id in the cache queryClient.setQueryData( - REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(chainId, serviceId), + REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(homeChainId, serviceId), stakingProgramId, ); }, - [queryClient, chainId, serviceId], + [queryClient, homeChainId, serviceId], ); return { ...response, setActiveStakingProgramId }; }; /** - * context provider responsible for determining the current active staking program, if any. + * context provider responsible for determining the current active staking programs. * It does so by checking if the current service is staked, and if so, which staking program it is staked in. * It also provides a method to update the active staking program id in state. */ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { - const { isLoading: isStakingProgramLoading, data: activeStakingProgramId } = + const { isLoading: isStakingProgramsLoading, data: activeStakingProgramId } = useGetActiveStakingProgramId(); return ( diff --git a/frontend/enums/Agent.ts b/frontend/enums/Agent.ts index 60689a920..e709e3994 100644 --- a/frontend/enums/Agent.ts +++ b/frontend/enums/Agent.ts @@ -1,6 +1,6 @@ export const AgentType = { PredictTrader: 'trader', - Optimus: 'optimus', + // Optimus: 'optimus', } as const; export type AgentType = (typeof AgentType)[keyof typeof AgentType]; diff --git a/frontend/hooks/useAgent.ts b/frontend/hooks/useAgent.ts deleted file mode 100644 index f9ebff42c..000000000 --- a/frontend/hooks/useAgent.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { AGENT_CONFIG } from '@/config/agents'; - -export const useAgent = () => AGENT_CONFIG.trader; // TODO: replace with dynamic agent selection diff --git a/frontend/hooks/useChainId.ts b/frontend/hooks/useChainId.ts deleted file mode 100644 index 2dcff5055..000000000 --- a/frontend/hooks/useChainId.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { GNOSIS_CHAIN_CONFIG } from '@/config/chains'; - -export const useChainId = () => GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with dynamic chain selection diff --git a/frontend/hooks/useRewardsHistory.ts b/frontend/hooks/useRewardsHistory.ts index 28c5db6c8..5b14e26c1 100644 --- a/frontend/hooks/useRewardsHistory.ts +++ b/frontend/hooks/useRewardsHistory.ts @@ -11,9 +11,8 @@ import { GNOSIS_REWARDS_HISTORY_SUBGRAPH_URL } from '@/constants/urls'; import { Address } from '@/types/Address'; import { Nullable } from '@/types/Util'; -import { useAgent } from './useAgent'; -import { useChainId } from './useChainId'; import { useServiceId } from './useService'; +import { useServices } from './useServices'; const ONE_DAY_IN_S = 24 * 60 * 60; const ONE_DAY_IN_MS = ONE_DAY_IN_S * 1000; @@ -90,8 +89,8 @@ export type Checkpoint = { }; const useTransformCheckpoints = () => { - const agent = useAgent(); - const chainId = useChainId(); + const { selectedAgentConfig } = useServices(); + const { serviceApi: agent, homeChainId: chainId } = selectedAgentConfig; return useCallback( ( @@ -125,11 +124,10 @@ const useTransformCheckpoints = () => { Number(checkpoint.epochLength) : checkpoints[index + 1]?.blockTimestamp ?? 0; - const stakingContractId = - agent.serviceApi.getStakingProgramIdByAddress( - chainId, - checkpoint.contractAddress as Address, - ); + const stakingContractId = agent.getStakingProgramIdByAddress( + chainId, + checkpoint.contractAddress as Address, + ); return { ...checkpoint, @@ -165,7 +163,9 @@ type CheckpointsResponse = { checkpoints: CheckpointResponse[] }; */ const useContractCheckpoints = () => { const serviceId = useServiceId(); - const chainId = useChainId(); + const { selectedAgentConfig } = useServices(); + const { homeChainId: chainId } = selectedAgentConfig; + const transformCheckpoints = useTransformCheckpoints(); return useQuery({ diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index d789f3fbc..c3f71d69a 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -5,7 +5,6 @@ import { MiddlewareDeploymentStatus } from '@/client'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { Address } from '@/types/Address'; -import { useChainId } from './useChainId'; import { useServices } from './useServices'; type ServiceChainIdAddressRecord = { @@ -87,12 +86,16 @@ export const useService = ({ * Hook to get service id */ export const useServiceId = () => { - const chainId = useChainId(); - const { selectedService, isFetched: isLoaded } = useServices(); + const { + selectedService, + selectedAgentConfig, + isFetched: isLoaded, + } = useServices(); + const { homeChainId } = selectedAgentConfig; const serviceConfigId = isLoaded && selectedService ? selectedService?.service_config_id : ''; const { service } = useService({ serviceConfigId }); - const serviceId = service?.chain_configs[chainId].chain_data?.token; + const serviceId = service?.chain_configs[homeChainId].chain_data?.token; return serviceId; }; diff --git a/frontend/hooks/useStakingContractDetails.ts b/frontend/hooks/useStakingContractDetails.ts index 9029f48ef..b5b01915b 100644 --- a/frontend/hooks/useStakingContractDetails.ts +++ b/frontend/hooks/useStakingContractDetails.ts @@ -1,16 +1,10 @@ -import { useQuery } from '@tanstack/react-query'; import { isNil } from 'lodash'; import { useContext } from 'react'; -import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; -import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingContractDetailsContext } from '@/context/StakingContractDetailsProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { Maybe } from '@/types/Util'; -import { useAgent } from './useAgent'; -import { useChainId } from './useChainId'; -import { useServiceId } from './useService'; +import { useServices } from './useServices'; export const useStakingContractContext = () => { const { @@ -42,13 +36,14 @@ export const useActiveStakingContractInfo = () => { const { selectedService } = useServices(); // TODO: find a better way to handle this, currently stops react lifecycle hooks being implemented below it - if (!selectedService || !activeStakingContractDetails) + if (!selectedService || !activeStakingContractDetails) { return { allStakingContractDetailsRecord, refetchActiveStakingContractDetails, setIsPaused, isPaused, }; + } const { serviceStakingState, @@ -110,41 +105,10 @@ export const useActiveStakingContractInfo = () => { }; }; -/** - * hook to get staking contract details by staking program - */ -export const useStakingContractDetailsByStakingProgram = ( - stakingProgramId: Maybe, - isPaused?: boolean, -) => { - const serviceId = useServiceId(); - const chainId = useChainId(); - const agent = useAgent(); - - return useQuery({ - queryKey: REACT_QUERY_KEYS.STAKING_CONTRACT_DETAILS_BY_STAKING_PROGRAM_KEY( - chainId, - serviceId!, - stakingProgramId!, - ), - queryFn: async () => { - return await agent.serviceApi.getStakingContractDetailsByServiceIdStakingProgram( - serviceId!, - stakingProgramId!, - chainId, - ); - }, - enabled: !!serviceId && !!stakingProgramId && !!chainId && !isPaused, - refetchInterval: !isPaused ? FIVE_SECONDS_INTERVAL : false, - refetchOnWindowFocus: false, - }); -}; - export const useStakingContractDetails = ( stakingProgramId: StakingProgramId, ) => { const { allStakingContractDetailsRecord } = useStakingContractContext(); - const stakingContractInfo = allStakingContractDetailsRecord?.[stakingProgramId]; diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index fdcfdd209..ab00f7ae2 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -1,34 +1,74 @@ import { useContext, useMemo } from 'react'; -import { STAKING_PROGRAM_ADDRESS } from '@/config/stakingPrograms'; -import { GNOSIS_STAKING_PROGRAMS } from '@/config/stakingPrograms/gnosis'; +import { + STAKING_PROGRAM_ADDRESS, + STAKING_PROGRAMS, + StakingProgramConfig, +} from '@/config/stakingPrograms'; import { StakingProgramContext } from '@/context/StakingProgramProvider'; +import { StakingProgramId } from '@/enums/StakingProgram'; -import { useChainId } from './useChainId'; +import { useServices } from './useServices'; /** * Hook to get the active staking program and its metadata. */ export const useStakingProgram = () => { - const chainId = useChainId(); - const { activeStakingProgramId, isActiveStakingProgramLoaded } = useContext( + const { isActiveStakingProgramLoaded, activeStakingProgramId } = useContext( StakingProgramContext, ); + const { selectedAgentConfig } = useServices(); + const { homeChainId } = selectedAgentConfig; + + const allStakingProgramsKeys = Object.keys(STAKING_PROGRAMS[homeChainId]); + const allStakingProgramNameAddressPair = STAKING_PROGRAM_ADDRESS[homeChainId]; const activeStakingProgramMeta = useMemo(() => { + if (!isActiveStakingProgramLoaded) return null; if (!activeStakingProgramId) return null; - return GNOSIS_STAKING_PROGRAMS[activeStakingProgramId]; - }, [activeStakingProgramId]); + if (activeStakingProgramId.length === 0) return null; + + return (allStakingProgramsKeys as StakingProgramId[]).reduce( + (acc, programId) => { + if (activeStakingProgramId.includes(programId)) { + acc[programId] = STAKING_PROGRAMS[homeChainId][programId]; + } + return acc; + }, + {} as Record, + ); + }, [ + homeChainId, + isActiveStakingProgramLoaded, + allStakingProgramsKeys, + activeStakingProgramId, + ]); const activeStakingProgramAddress = useMemo(() => { if (!activeStakingProgramId) return null; - return STAKING_PROGRAM_ADDRESS[chainId][activeStakingProgramId]; - }, [chainId, activeStakingProgramId]); + if (activeStakingProgramId.length === 0) return null; + + return ( + Object.keys(allStakingProgramNameAddressPair) as StakingProgramId[] + ).reduce( + (acc, programId) => { + if (activeStakingProgramId.includes(programId)) { + acc[programId] = allStakingProgramNameAddressPair[programId]; + } + return acc; + }, + {} as Record, + ); + }, [allStakingProgramNameAddressPair, activeStakingProgramId]); return { isActiveStakingProgramLoaded, activeStakingProgramId, activeStakingProgramAddress, activeStakingProgramMeta, + + // all staking programs + allStakingProgramIds: Object.keys(allStakingProgramNameAddressPair), + allStakingProgramAddress: Object.values(allStakingProgramNameAddressPair), }; }; diff --git a/frontend/service/agents/PredictTrader.ts b/frontend/service/agents/PredictTrader.ts index f0012cdad..c16141dd1 100644 --- a/frontend/service/agents/PredictTrader.ts +++ b/frontend/service/agents/PredictTrader.ts @@ -7,6 +7,7 @@ import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; import { StakingContractDetails, StakingRewardsInfo } from '@/types/Autonolas'; +import { Maybe } from '@/types/Util'; import { ONE_YEAR, StakedAgentService } from './StakedAgentService'; @@ -144,8 +145,8 @@ export abstract class PredictTraderService extends StakedAgentService { serviceId: number, stakingProgramId: StakingProgramId, chainId: ChainId = ChainId.Gnosis, - ): Promise | undefined> => { - if (!serviceId) return; + ): Promise>> => { + if (!serviceId) return null; const { multicallProvider } = PROVIDERS[chainId]; diff --git a/frontend/service/agents/StakedAgentService.ts b/frontend/service/agents/StakedAgentService.ts index 186a8d462..935d4e9c2 100644 --- a/frontend/service/agents/StakedAgentService.ts +++ b/frontend/service/agents/StakedAgentService.ts @@ -21,12 +21,12 @@ import { ContractType } from '@/enums/Contract'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; -import { Nullable } from '@/types/Util'; +import { Maybe, Nullable } from '@/types/Util'; export const ONE_YEAR = 1 * 24 * 60 * 60 * 365; /** - * + * Staked agent service class. */ export abstract class StakedAgentService { abstract activityCheckerContract: MulticallContract; @@ -34,15 +34,31 @@ export abstract class StakedAgentService { abstract serviceRegistryTokenUtilityContract: MulticallContract; abstract getStakingRewardsInfo: Promise; - abstract getAvailableRewardsForEpoch: Promise; - abstract getStakingContractInfo: Promise; - abstract getStakingContractInfoByServiceIdStakingProgramId: Promise; - abstract getStakingContractInfoByStakingProgramId: Promise; + abstract getAgentStakingRewardsInfo( + agentMultisigAddress: Address, + serviceId: number, + stakingProgramId: StakingProgramId, + chainId: ChainId, + ): Promise; + abstract getAvailableRewardsForEpoch( + stakingProgramId: StakingProgramId, + chainId: ChainId, + ): Promise; + abstract getStakingContractDetailsByServiceIdStakingProgram( + serviceId: number, + stakingProgramId: StakingProgramId, + chainId: ChainId, + ): Promise; + abstract getStakingContractDetailsByName( + stakingProgramId: StakingProgramId, + chainId: ChainId, + ): Promise; + abstract getInstance(): StakedAgentService; static getCurrentStakingProgramByServiceId = async ( serviceId: number, chainId: ChainId, - ): Promise => { + ): Promise> => { try { const { multicallProvider } = PROVIDERS[chainId]; @@ -74,9 +90,9 @@ export abstract class StakedAgentService { } // return the staking program id - return stakingProgramEntries[ - activeStakingProgramIndex - ][0] as StakingProgramId; + const activeStakingProgram = + stakingProgramEntries[activeStakingProgramIndex][0]; + return activeStakingProgram as StakingProgramId; } catch (error) { console.error('Error while getting current staking program', error); return null; diff --git a/frontend/types/Agent.ts b/frontend/types/Agent.ts new file mode 100644 index 000000000..4f95eb552 --- /dev/null +++ b/frontend/types/Agent.ts @@ -0,0 +1,12 @@ +import { ChainId } from '@/enums/Chain'; +import { PredictTraderService } from '@/service/agents/PredictTrader'; + +export type StakedAgentServiceInstance = PredictTraderService; +export type AgentConfig = { + name: string; + homeChainId: ChainId; + requiresAgentSafesOn: ChainId[]; + agentSafeFundingRequirements: Record; + requiresMasterSafesOn: ChainId[]; + serviceApi: typeof PredictTraderService; +}; From 3a6e8fe4ec017de7ae4d485e90c584c310fda984 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 10:42:45 +0000 Subject: [PATCH 247/463] refactor: streamline wallet balance calculation logic --- frontend/context/BalanceProvider.tsx | 386 +++++++++++++++++---------- 1 file changed, 244 insertions(+), 142 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index d32476561..145cf57b5 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -1,4 +1,3 @@ -import { BigNumberish } from 'ethers'; import { Contract as MulticallContract } from 'ethers-multicall'; import { createContext, @@ -8,23 +7,31 @@ import { useCallback, useContext, useEffect, + useMemo, useState, } from 'react'; +import { useInterval } from 'usehooks-ts'; import { ERC20_BALANCE_OF_STRING_FRAGMENT } from '@/abis/erc20'; import { MiddlewareServiceResponse } from '@/client'; import { TOKEN_CONFIG, TokenType } from '@/config/tokens'; +import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { PROVIDERS } from '@/constants/providers'; +import { + LOW_AGENT_SAFE_BALANCE, + LOW_MASTER_SAFE_BALANCE, +} from '@/constants/thresholds'; import { ChainId } from '@/enums/Chain'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { TokenSymbol } from '@/enums/Token'; -import { Wallets, WalletType } from '@/enums/Wallet'; +import { WalletOwnerType, Wallets, WalletType } from '@/enums/Wallet'; import { useServices } from '@/hooks/useServices'; import { GetServiceRegistryInfoResponse, StakedAgentService, } from '@/service/agents/StakedAgentService'; import { Address } from '@/types/Address'; +import { formatEther } from '@/utils/numberFormatters'; import { OnlineStatusContext } from './OnlineStatusProvider'; import { WalletContext } from './WalletProvider'; @@ -32,21 +39,33 @@ import { WalletContext } from './WalletProvider'; export const BalanceContext = createContext<{ isLoaded: boolean; setIsLoaded: Dispatch>; - totalOlasBalance?: number; - isLowBalance: boolean; updateBalances: () => Promise; setIsPaused: Dispatch>; - walletBalances: BalanceResult[]; - stakedBalances: CrossChainStakedBalances; + walletBalances: WalletBalanceResult[]; + stakedBalances?: CrossChainStakedBalances; + totalOlasBalance?: number; + totalEthBalance?: number; + totalStakedOlasBalance?: number; + lowBalances?: { + serviceConfigId: string; + chainId: ChainId; + walletAddress: Address; + balance: number; + expectedBalance: number; + }[]; + isPaused: boolean; }>({ isLoaded: false, setIsLoaded: () => {}, - totalOlasBalance: undefined, - isLowBalance: false, updateBalances: async () => {}, + isPaused: false, setIsPaused: () => {}, walletBalances: [], stakedBalances: {}, + totalOlasBalance: 0, + totalEthBalance: 0, + totalStakedOlasBalance: 0, + lowBalances: [], }); export const BalanceProvider = ({ children }: PropsWithChildren) => { @@ -58,79 +77,158 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { const [isLoaded, setIsLoaded] = useState(false); const [isPaused, setIsPaused] = useState(false); + const [isUpdatingBalances, setIsUpdatingBalances] = useState(false); - const [walletBalances, setWalletBalances] = useState([]); + const [walletBalances, setWalletBalances] = useState( + [], + ); const [stakedBalances, setStakedBalances] = useState(); + const totalEthBalance = useMemo(() => { + if (!isLoaded) return; + return walletBalances.reduce((acc, walletBalance) => { + if (walletBalance.isNative) { + return acc + walletBalance.balance; + } + return acc; + }, 0); + }, [isLoaded, walletBalances]); + + const totalOlasBalance = useMemo(() => { + if (!isLoaded) return; + return walletBalances.reduce((acc, walletBalance) => { + if (walletBalance.symbol === TokenSymbol.OLAS) { + return acc + walletBalance.balance; + } + return acc; + }, 0); + }, [isLoaded, walletBalances]); + + const totalStakedOlasBalance = useMemo(() => { + if (!stakedBalances) return 0; + + return Object.values(stakedBalances).reduce( + (serviceAcc, serviceBalances) => { + return ( + serviceAcc + + Object.values(serviceBalances).reduce((chainAcc, chainBalance) => { + return ( + chainAcc + + (chainBalance.olasBondBalance || 0) + + (chainBalance.olasDepositBalance || 0) + ); + }, 0) + ); + }, + 0, + ); + }, [stakedBalances]); + + /** + * An array of wallet address that have low native token balances + */ + const lowBalanceWalletAddresses = useMemo< + { + serviceConfigId: string; + chainId: ChainId; + walletAddress: Address; + balance: number; + expectedBalance: number; + }[] + >(() => { + const result = []; + + for (const service of services ?? []) { + const serviceId = service.service_config_id; + const serviceHomeChainId = service.home_chain_id; + const serviceStakedBalances = stakedBalances?.[serviceId]; + if (!serviceStakedBalances) continue; + + // get addresses for master safe and agent home chain safe + + const masterSafeAddress = wallets?.find( + (wallet) => + wallet.owner === WalletOwnerType.Master && + wallet.type === WalletType.Safe && + wallet.chainId === service.home_chain_id, + ); + + const stakedAgentSafeAddress = + service.chain_configs[serviceHomeChainId].chain_data.multisig; + + // skip invalid service + if (!masterSafeAddress && !stakedAgentSafeAddress) continue; + + // balances + const masterSafeBalanceResult = walletBalances.find( + (balance) => + balance.walletAddress === masterSafeAddress?.address && + balance.isNative, + ); + + const stakedAgentSafeBalanceResult = walletBalances.find( + (balance) => + balance.walletAddress === stakedAgentSafeAddress && balance.isNative, + ); + + if ( + masterSafeBalanceResult && + masterSafeBalanceResult?.balance < LOW_MASTER_SAFE_BALANCE // TODO: use agent specific threshold + ) { + result.push({ + serviceConfigId: service.service_config_id, + chainId: serviceHomeChainId, + walletAddress: masterSafeBalanceResult.walletAddress, + balance: masterSafeBalanceResult.balance, + expectedBalance: LOW_MASTER_SAFE_BALANCE, + }); + } + + if ( + stakedAgentSafeBalanceResult && + stakedAgentSafeBalanceResult?.balance < LOW_AGENT_SAFE_BALANCE //TODO: use agent specific threshold + ) { + result.push({ + serviceConfigId: service.service_config_id, + chainId: serviceHomeChainId, + walletAddress: stakedAgentSafeBalanceResult.walletAddress, + balance: stakedAgentSafeBalanceResult.balance, + expectedBalance: LOW_AGENT_SAFE_BALANCE, + }); + } + } + + return result; + }, [services, stakedBalances, wallets, walletBalances]); + const updateBalances = useCallback(async () => { if (wallets && services) { - getCrossChainWalletBalances(wallets).then((balances) => { - setWalletBalances(balances); - setIsLoaded(true); - }); + setIsUpdatingBalances(true); - getCrossChainStakedBalances(services).then((balances) => { - setStakedBalances(balances); - }); + await Promise.allSettled([ + getCrossChainWalletBalances(wallets).then((balances) => { + setWalletBalances(balances); + setIsLoaded(true); + }), + getCrossChainStakedBalances(services).then((balances) => { + setStakedBalances(balances); + }), + ]) + .then(() => setIsLoaded(true)) + .finally(() => setIsUpdatingBalances(false)); } }, [services, wallets]); useEffect(() => { - if (!isLoaded) updateBalances(); - }, [isLoaded, updateBalances]); - - // // TODO: refactor to parse `walletbalances` - - // const totalEthBalance: number | undefined = useMemo(() => { - // if (!isLoaded) return; - // return Object.values(walletBalances).reduce( - // (acc: number, walletBalance) => acc + walletBalance.ETH, - // 0, - // ); - // }, [isLoaded, walletBalances]); - - // const totalOlasBalance: number | undefined = useMemo(() => { - // if (!isLoaded) return; - - // const sumWalletBalances = Object.values(walletBalances).reduce( - // (acc: number, walletBalance) => acc + walletBalance.OLAS, - // 0, - // ); - - // const total = - // sumWalletBalances + - // (olasDepositBalance ?? 0) + - // (olasBondBalance ?? 0) + - // (optimisticRewardsEarnedForEpoch ?? 0) + - // (accruedServiceStakingRewards ?? 0); - - // return total; - // }, [accruedServiceStakingRewards, isLoaded, optimisticRewardsEarnedForEpoch]); - - // const totalOlasStakedBalance: number | undefined = useMemo(() => { - // if (!isLoaded) return; - // return (olasBondBalance ?? 0) + (olasDepositBalance ?? 0); - // }, [isLoaded]); - - // // TODO: include in walletBalances - // // const isLowBalance = useMemo(() => { - // // if (!masterSafeBalance || !agentSafeBalance) return false; - // // if ( - // // masterSafeBalance.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; - // // }, [masterSafeBalance, agentSafeBalance]); - - // useInterval( - // () => { - // updateBalances(); - // }, - // isPaused || !isOnline ? null : FIVE_SECONDS_INTERVAL, - // ); + // update balances once on load, then use interval + if (!isOnline) return; + if (isUpdatingBalances || isLoaded) return; + + updateBalances(); + }, [isLoaded, isOnline, isUpdatingBalances, updateBalances]); + + useInterval(updateBalances, FIVE_SECONDS_INTERVAL); return ( { isLoaded, setIsLoaded, walletBalances, - stakedBalances: stakedBalances || {}, + stakedBalances, updateBalances, + isPaused, setIsPaused, - isLowBalance: false, + totalOlasBalance, + totalEthBalance, + totalStakedOlasBalance, + lowBalances: lowBalanceWalletAddresses, }} > {children} @@ -149,17 +251,17 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { ); }; -type BalanceResult = { +type WalletBalanceResult = { walletAddress: Address; chainId: ChainId; symbol: TokenSymbol; isNative: boolean; - balance: BigNumberish; + balance: number; }; const getCrossChainWalletBalances = async ( wallets: Wallets, -): Promise => { +): Promise => { const providerEntries = Object.entries(PROVIDERS); // Get balances for each chain @@ -170,82 +272,82 @@ const getCrossChainWalletBalances = async ( // Get tokens for this chain const tokens = TOKEN_CONFIG[chainId]; - if (!tokens) return [] as BalanceResult[]; + if (!tokens) return [] as WalletBalanceResult[]; // Create balance checking promises for all tokens and wallets - const chainBalancePromises: Promise[] = Object.entries( - tokens, - ).map(async ([symbolKey, tokenConfig]) => { - const symbol = symbolKey as TokenSymbol; - - const results: BalanceResult[] = []; - const isNative = tokenConfig.tokenType === TokenType.NativeGas; - const isErc20 = tokenConfig.tokenType === TokenType.Erc20; - - // Filter relevant wallets - const relevantWallets = wallets.filter((wallet) => { - const isEoa = wallet.type === WalletType.EOA; - const isSafe = wallet.type === WalletType.Safe; - const isOnSameChain = isEoa || wallet.chainId === chainId; - return isEoa || (isSafe && isOnSameChain); + const chainBalancePromises: Promise[] = + Object.entries(tokens).map(async ([symbolKey, tokenConfig]) => { + const symbol = symbolKey as TokenSymbol; + + const results: WalletBalanceResult[] = []; + const isNative = tokenConfig.tokenType === TokenType.NativeGas; + const isErc20 = tokenConfig.tokenType === TokenType.Erc20; + + // Filter relevant wallets + const relevantWallets = wallets.filter((wallet) => { + const isEoa = wallet.type === WalletType.EOA; + const isSafe = wallet.type === WalletType.Safe; + const isOnSameChain = isEoa || wallet.chainId === chainId; + return isEoa || (isSafe && isOnSameChain); + }); + + if (isNative) { + // Handle native token balances + const nativeBalances = await Promise.all( + relevantWallets.map(async (wallet) => { + const balance = await chainMulticallProvider.getEthBalance( + wallet.address, + ); + return { + walletAddress: wallet.address, + chainId, + symbol, + isNative: true, + balance: +formatEther(balance), + } as WalletBalanceResult; + }), + ); + results.push(...nativeBalances); + } + + if (isErc20) { + // Create ERC20 contract interface for multicall + const erc20Contract = new MulticallContract( + tokenConfig.address, + ERC20_BALANCE_OF_STRING_FRAGMENT, + ); + + // Prepare multicall for ERC20 balances + const erc20Calls = relevantWallets.map((wallet) => + erc20Contract.balanceOf(wallet.address), + ); + + // Execute multicall + const erc20Balances = + await chainMulticallProvider.all(erc20Calls); + + // Map results to balance objects + const erc20Results = relevantWallets.map((wallet, index) => ({ + walletAddress: wallet.address, + chainId, + symbol, + isNative: false, + balance: erc20Balances[index], + })) as WalletBalanceResult[]; + + results.push(...erc20Results); + } + + return results; }); - if (isNative) { - // Handle native token balances - const nativeBalances = await Promise.all( - relevantWallets.map(async (wallet) => { - const balance = await chainMulticallProvider.getEthBalance( - wallet.address, - ); - return { - walletAddress: wallet.address, - chainId, - symbol, - isNative: true, - balance, - } as BalanceResult; - }), - ); - results.push(...nativeBalances); - } - - if (isErc20) { - // Create ERC20 contract interface for multicall - const erc20Contract = new MulticallContract( - tokenConfig.address, - ERC20_BALANCE_OF_STRING_FRAGMENT, - ); - - // Prepare multicall for ERC20 balances - const erc20Calls = relevantWallets.map((wallet) => - erc20Contract.balanceOf(wallet.address), - ); - - // Execute multicall - const erc20Balances = await chainMulticallProvider.all(erc20Calls); - - // Map results to balance objects - const erc20Results = relevantWallets.map((wallet, index) => ({ - walletAddress: wallet.address, - chainId, - symbol, - isNative: false, - balance: erc20Balances[index], - })) as BalanceResult[]; - - results.push(...erc20Results); - } - - return results; - }); - // Wait for all token balance promises to resolve and handle results const chainResults = await Promise.allSettled(chainBalancePromises); // Filter and flatten successful results return chainResults .filter( - (result): result is PromiseFulfilledResult => + (result): result is PromiseFulfilledResult => result.status === 'fulfilled', ) .map((result) => result.value) @@ -257,7 +359,7 @@ const getCrossChainWalletBalances = async ( // Filter and flatten successful results from all chains return balanceResults .filter( - (result): result is PromiseFulfilledResult => + (result): result is PromiseFulfilledResult => result.status === 'fulfilled', ) .map((result) => result.value) From 085f036c9c9ac91c71621d38bb0e1d9f0e3d615b Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 10:55:16 +0000 Subject: [PATCH 248/463] refactor: clean up --- frontend/context/BalanceProvider.tsx | 347 ++++++++++++--------------- 1 file changed, 148 insertions(+), 199 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 145cf57b5..8b4119a1a 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -26,10 +26,7 @@ import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceS import { TokenSymbol } from '@/enums/Token'; import { WalletOwnerType, Wallets, WalletType } from '@/enums/Wallet'; import { useServices } from '@/hooks/useServices'; -import { - GetServiceRegistryInfoResponse, - StakedAgentService, -} from '@/service/agents/StakedAgentService'; +import { StakedAgentService } from '@/service/agents/StakedAgentService'; import { Address } from '@/types/Address'; import { formatEther } from '@/utils/numberFormatters'; @@ -42,11 +39,11 @@ export const BalanceContext = createContext<{ updateBalances: () => Promise; setIsPaused: Dispatch>; walletBalances: WalletBalanceResult[]; - stakedBalances?: CrossChainStakedBalances; - totalOlasBalance?: number; - totalEthBalance?: number; - totalStakedOlasBalance?: number; - lowBalances?: { + stakedBalances: CrossChainStakedBalances; + totalOlasBalance: number; + totalEthBalance: number; + totalStakedOlasBalance: number; + lowBalances: { serviceConfigId: string; chainId: ChainId; walletAddress: Address; @@ -72,8 +69,6 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); const { wallets } = useContext(WalletContext); const { services } = useServices(); - // const { optimisticRewardsEarnedForEpoch, accruedServiceStakingRewards } = - // useContext(RewardContext); const [isLoaded, setIsLoaded] = useState(false); const [isPaused, setIsPaused] = useState(false); @@ -83,10 +78,10 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { [], ); const [stakedBalances, setStakedBalances] = - useState(); + useState({}); const totalEthBalance = useMemo(() => { - if (!isLoaded) return; + if (!isLoaded) return 0; return walletBalances.reduce((acc, walletBalance) => { if (walletBalance.isNative) { return acc + walletBalance.balance; @@ -96,7 +91,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { }, [isLoaded, walletBalances]); const totalOlasBalance = useMemo(() => { - if (!isLoaded) return; + if (!isLoaded) return 0; return walletBalances.reduce((acc, walletBalance) => { if (walletBalance.symbol === TokenSymbol.OLAS) { return acc + walletBalance.balance; @@ -106,8 +101,6 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { }, [isLoaded, walletBalances]); const totalStakedOlasBalance = useMemo(() => { - if (!stakedBalances) return 0; - return Object.values(stakedBalances).reduce( (serviceAcc, serviceBalances) => { return ( @@ -126,45 +119,44 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { }, [stakedBalances]); /** - * An array of wallet address that have low native token balances + * An array of wallet addresses that have low native token balances */ - const lowBalanceWalletAddresses = useMemo< - { + const lowBalances = useMemo(() => { + const result: { serviceConfigId: string; chainId: ChainId; walletAddress: Address; balance: number; expectedBalance: number; - }[] - >(() => { - const result = []; + }[] = []; + + if (!services || !wallets || !walletBalances) return result; - for (const service of services ?? []) { + for (const service of services) { const serviceId = service.service_config_id; const serviceHomeChainId = service.home_chain_id; - const serviceStakedBalances = stakedBalances?.[serviceId]; + const serviceStakedBalances = stakedBalances[serviceId]; if (!serviceStakedBalances) continue; - // get addresses for master safe and agent home chain safe - - const masterSafeAddress = wallets?.find( + // Get addresses for master safe and agent home chain safe + const masterSafeWallet = wallets.find( (wallet) => wallet.owner === WalletOwnerType.Master && wallet.type === WalletType.Safe && wallet.chainId === service.home_chain_id, ); + const masterSafeAddress = masterSafeWallet?.address; const stakedAgentSafeAddress = - service.chain_configs[serviceHomeChainId].chain_data.multisig; + service.chain_configs[serviceHomeChainId]?.chain_data.multisig; - // skip invalid service + // Skip invalid service if (!masterSafeAddress && !stakedAgentSafeAddress) continue; - // balances + // Balances const masterSafeBalanceResult = walletBalances.find( (balance) => - balance.walletAddress === masterSafeAddress?.address && - balance.isNative, + balance.walletAddress === masterSafeAddress && balance.isNative, ); const stakedAgentSafeBalanceResult = walletBalances.find( @@ -174,27 +166,27 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { if ( masterSafeBalanceResult && - masterSafeBalanceResult?.balance < LOW_MASTER_SAFE_BALANCE // TODO: use agent specific threshold + masterSafeBalanceResult.balance < LOW_MASTER_SAFE_BALANCE // TODO: use agent specific threshold ) { result.push({ serviceConfigId: service.service_config_id, chainId: serviceHomeChainId, walletAddress: masterSafeBalanceResult.walletAddress, balance: masterSafeBalanceResult.balance, - expectedBalance: LOW_MASTER_SAFE_BALANCE, + expectedBalance: LOW_MASTER_SAFE_BALANCE, // TODO: use agent specific threshold }); } if ( stakedAgentSafeBalanceResult && - stakedAgentSafeBalanceResult?.balance < LOW_AGENT_SAFE_BALANCE //TODO: use agent specific threshold + stakedAgentSafeBalanceResult.balance < LOW_AGENT_SAFE_BALANCE // TODO: use agent specific threshold ) { result.push({ serviceConfigId: service.service_config_id, chainId: serviceHomeChainId, walletAddress: stakedAgentSafeBalanceResult.walletAddress, balance: stakedAgentSafeBalanceResult.balance, - expectedBalance: LOW_AGENT_SAFE_BALANCE, + expectedBalance: LOW_AGENT_SAFE_BALANCE, // TODO: use agent specific threshold }); } } @@ -206,29 +198,35 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { if (wallets && services) { setIsUpdatingBalances(true); - await Promise.allSettled([ - getCrossChainWalletBalances(wallets).then((balances) => { - setWalletBalances(balances); - setIsLoaded(true); - }), - getCrossChainStakedBalances(services).then((balances) => { - setStakedBalances(balances); - }), - ]) - .then(() => setIsLoaded(true)) - .finally(() => setIsUpdatingBalances(false)); + try { + const [walletBalancesResult, stakedBalancesResult] = await Promise.all([ + getCrossChainWalletBalances(wallets), + getCrossChainStakedBalances(services), + ]); + + setWalletBalances(walletBalancesResult); + setStakedBalances(stakedBalancesResult); + setIsLoaded(true); + } catch (error) { + console.error('Error updating balances:', error); + } finally { + setIsUpdatingBalances(false); + } } }, [services, wallets]); useEffect(() => { - // update balances once on load, then use interval - if (!isOnline) return; - if (isUpdatingBalances || isLoaded) return; + // Update balances once on load, then use interval + if (!isOnline || isUpdatingBalances || isLoaded) return; updateBalances(); - }, [isLoaded, isOnline, isUpdatingBalances, updateBalances]); + }, [isOnline, isUpdatingBalances, isLoaded, updateBalances]); - useInterval(updateBalances, FIVE_SECONDS_INTERVAL); + useInterval(() => { + if (!isPaused && isOnline && !isUpdatingBalances) { + updateBalances(); + } + }, FIVE_SECONDS_INTERVAL); return ( { totalOlasBalance, totalEthBalance, totalStakedOlasBalance, - lowBalances: lowBalanceWalletAddresses, + lowBalances, }} > {children} @@ -262,111 +260,70 @@ type WalletBalanceResult = { const getCrossChainWalletBalances = async ( wallets: Wallets, ): Promise => { - const providerEntries = Object.entries(PROVIDERS); - - // Get balances for each chain - const balanceResults = await Promise.allSettled( - providerEntries.map( - async ([chainIdKey, { multicallProvider: chainMulticallProvider }]) => { - const chainId = +chainIdKey as ChainId; - - // Get tokens for this chain - const tokens = TOKEN_CONFIG[chainId]; - if (!tokens) return [] as WalletBalanceResult[]; - - // Create balance checking promises for all tokens and wallets - const chainBalancePromises: Promise[] = - Object.entries(tokens).map(async ([symbolKey, tokenConfig]) => { - const symbol = symbolKey as TokenSymbol; - - const results: WalletBalanceResult[] = []; - const isNative = tokenConfig.tokenType === TokenType.NativeGas; - const isErc20 = tokenConfig.tokenType === TokenType.Erc20; - - // Filter relevant wallets - const relevantWallets = wallets.filter((wallet) => { - const isEoa = wallet.type === WalletType.EOA; - const isSafe = wallet.type === WalletType.Safe; - const isOnSameChain = isEoa || wallet.chainId === chainId; - return isEoa || (isSafe && isOnSameChain); - }); - - if (isNative) { - // Handle native token balances - const nativeBalances = await Promise.all( - relevantWallets.map(async (wallet) => { - const balance = await chainMulticallProvider.getEthBalance( - wallet.address, - ); - return { - walletAddress: wallet.address, - chainId, - symbol, - isNative: true, - balance: +formatEther(balance), - } as WalletBalanceResult; - }), - ); - results.push(...nativeBalances); - } - - if (isErc20) { - // Create ERC20 contract interface for multicall - const erc20Contract = new MulticallContract( - tokenConfig.address, - ERC20_BALANCE_OF_STRING_FRAGMENT, - ); - - // Prepare multicall for ERC20 balances - const erc20Calls = relevantWallets.map((wallet) => - erc20Contract.balanceOf(wallet.address), - ); - - // Execute multicall - const erc20Balances = - await chainMulticallProvider.all(erc20Calls); - - // Map results to balance objects - const erc20Results = relevantWallets.map((wallet, index) => ({ - walletAddress: wallet.address, - chainId, - symbol, - isNative: false, - balance: erc20Balances[index], - })) as WalletBalanceResult[]; - - results.push(...erc20Results); - } - - return results; - }); - - // Wait for all token balance promises to resolve and handle results - const chainResults = await Promise.allSettled(chainBalancePromises); - - // Filter and flatten successful results - return chainResults - .filter( - (result): result is PromiseFulfilledResult => - result.status === 'fulfilled', - ) - .map((result) => result.value) - .flat(); - }, - ), - ); + const balanceResults: WalletBalanceResult[] = []; + + for (const [chainIdKey, { multicallProvider }] of Object.entries(PROVIDERS)) { + const chainId = Number(chainIdKey) as ChainId; + + const tokens = TOKEN_CONFIG[chainId]; + if (!tokens) continue; + + const relevantWallets = wallets.filter((wallet) => { + const isEoa = wallet.type === WalletType.EOA; + const isSafe = wallet.type === WalletType.Safe; + const isOnSameChain = isEoa || wallet.chainId === chainId; + return isEoa || (isSafe && isOnSameChain); + }); + + for (const [symbolKey, tokenConfig] of Object.entries(tokens)) { + const symbol = symbolKey as TokenSymbol; + + const isNative = tokenConfig.tokenType === TokenType.NativeGas; + const isErc20 = tokenConfig.tokenType === TokenType.Erc20; + + if (isNative) { + const nativeBalancePromises = relevantWallets.map(async (wallet) => { + const balance = await multicallProvider.getEthBalance(wallet.address); + return { + walletAddress: wallet.address, + chainId, + symbol, + isNative: true, + balance: Number(formatEther(balance)), + } as WalletBalanceResult; + }); - // Filter and flatten successful results from all chains - return balanceResults - .filter( - (result): result is PromiseFulfilledResult => - result.status === 'fulfilled', - ) - .map((result) => result.value) - .flat(); -}; + const nativeBalances = await Promise.all(nativeBalancePromises); + balanceResults.push(...nativeBalances); + } + + if (isErc20) { + const erc20Contract = new MulticallContract( + tokenConfig.address, + ERC20_BALANCE_OF_STRING_FRAGMENT, + ); + + const erc20Calls = relevantWallets.map((wallet) => + erc20Contract.balanceOf(wallet.address), + ); + + const erc20Balances = await multicallProvider.all(erc20Calls); + + const erc20Results = relevantWallets.map((wallet, index) => ({ + walletAddress: wallet.address, + chainId, + symbol, + isNative: false, + balance: Number(formatEther(erc20Balances[index])), + })) as WalletBalanceResult[]; + + balanceResults.push(...erc20Results); + } + } + } -// TODO: implement staked balances cross-chain for all master safes + return balanceResults; +}; type CrossChainStakedBalances = { [serviceId: string]: { @@ -382,57 +339,53 @@ const getCrossChainStakedBalances = async ( ): Promise => { const result: CrossChainStakedBalances = {}; - // for each service, create a nest objects for chain staked balances - const registryInfoCalls: Promise[] = []; - services.forEach((service) => { + const registryInfoPromises = services.map(async (service) => { + const serviceId = service.service_config_id; const homeChainId = service.home_chain_id; const homeChainConfig = service.chain_configs[homeChainId]; const { multisig, token } = homeChainConfig.chain_data; if (!multisig || !token) { - registryInfoCalls.push( - Promise.resolve({ - depositValue: 0, - bondValue: 0, - serviceState: ServiceRegistryL2ServiceState.NonExistent, - }), - ); - return; + return { + serviceId, + homeChainId, + depositValue: 0, + bondValue: 0, + serviceState: ServiceRegistryL2ServiceState.NonExistent, + }; } - registryInfoCalls.push( - StakedAgentService.getServiceRegistryInfo(multisig, token, homeChainId), + const registryInfo = await StakedAgentService.getServiceRegistryInfo( + multisig, + token, + homeChainId, ); + + return { + serviceId, + homeChainId, + ...registryInfo, + }; }); // TODO: chunk and batch multicalls by chain, // currently Promise is returned by `StakedAgentService.getServiceRegistryInfo` // will not scale well with large number of services - const registryInfos = await Promise.allSettled(registryInfoCalls); + const registryInfos = await Promise.allSettled(registryInfoPromises); - registryInfos.forEach((res, index) => { + registryInfos.forEach((res) => { if (res.status === 'fulfilled') { - const { depositValue, bondValue, serviceState } = - res.value as GetServiceRegistryInfoResponse; - const serviceId = services[index].service_config_id; - const homeChainId = services[index].home_chain_id; + const { serviceId, homeChainId, depositValue, bondValue, serviceState } = + res.value; if (!result[serviceId]) result[serviceId] = {}; - if (!result[serviceId][homeChainId]) - result[serviceId][homeChainId] = { - olasBondBalance: 0, - olasDepositBalance: 0, - }; - - // service state is used to determine the correct bond and deposit balances - // stops funds from being displayed incorrectly during service state transitions - const serviceStateBondDepositBalances = correctBondDepositByServiceState({ + result[serviceId][homeChainId] = correctBondDepositByServiceState({ olasBondBalance: bondValue, olasDepositBalance: depositValue, serviceState, }); - - result[serviceId][homeChainId] = serviceStateBondDepositBalances; + } else { + console.error('Error fetching registry info:', res.reason); } }); @@ -457,10 +410,6 @@ const correctBondDepositByServiceState = ({ } => { switch (serviceState) { case ServiceRegistryL2ServiceState.NonExistent: - return { - olasBondBalance: 0, - olasDepositBalance: 0, - }; case ServiceRegistryL2ServiceState.PreRegistration: return { olasBondBalance: 0, @@ -469,24 +418,24 @@ const correctBondDepositByServiceState = ({ case ServiceRegistryL2ServiceState.ActiveRegistration: return { olasBondBalance: 0, - olasDepositBalance, + olasDepositBalance: olasDepositBalance, }; case ServiceRegistryL2ServiceState.FinishedRegistration: - return { - olasBondBalance, - olasDepositBalance, - }; case ServiceRegistryL2ServiceState.Deployed: return { - olasBondBalance, - olasDepositBalance, + olasBondBalance: olasBondBalance, + olasDepositBalance: olasDepositBalance, }; case ServiceRegistryL2ServiceState.TerminatedBonded: return { - olasBondBalance, + olasBondBalance: olasBondBalance, olasDepositBalance: 0, }; default: - throw new Error('Invalid service state'); + console.error('Invalid service state'); + return { + olasBondBalance: olasBondBalance, + olasDepositBalance: olasDepositBalance, + }; } }; From 6652d73b3b5bc781707bd9a9d83d436b2517f1e3 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 11:25:49 +0000 Subject: [PATCH 249/463] refactor: setCrossChainStakedBalances to array instead, object is unhelpful --- .../AgentButton/AgentNotRunningButton.tsx | 5 +- frontend/components/MainPage/header/index.tsx | 4 +- frontend/components/MainPage/index.tsx | 6 +- .../AlertSections/LowTradingBalanceAlert.tsx | 4 +- .../MainPage/sections/GasBalanceSection.tsx | 6 +- .../MainPage/sections/OlasBalanceSection.tsx | 4 +- .../RewardsSection/NotifyRewardsModal.tsx | 4 +- .../sections/RewardsSection/RewardsStreak.tsx | 4 +- .../sections/RewardsSection/index.tsx | 4 +- .../CantMigrateAlert.tsx | 4 +- .../StakingContractSection/MigrateButton.tsx | 4 +- .../StakingContractSection/useMigrate.tsx | 4 +- .../SettingsPage/AddBackupWalletPage.tsx | 4 +- .../SettingsPage/DebugInfoSection.tsx | 4 +- .../components/SetupPage/SetupWelcome.tsx | 4 +- .../components/YourWalletPage/YourAgent.tsx | 4 +- frontend/components/YourWalletPage/index.tsx | 8 +- frontend/context/BalanceProvider.tsx | 101 ++++++++---------- frontend/hooks/useBalance.ts | 5 - frontend/hooks/useBalanceContext.ts | 35 ++++++ frontend/hooks/useLogs.ts | 4 +- frontend/hooks/useNeedsFunds.ts | 4 +- frontend/hooks/useService.ts | 9 ++ 23 files changed, 132 insertions(+), 103 deletions(-) delete mode 100644 frontend/hooks/useBalance.ts create mode 100644 frontend/hooks/useBalanceContext.ts diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index fc4fc0bac..b3957eda4 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -5,7 +5,7 @@ import { MiddlewareChain, MiddlewareDeploymentStatus } from '@/client'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; @@ -47,7 +47,8 @@ export const AgentNotRunningButton = () => { totalOlasStakedBalance, totalEthBalance, updateBalances, - } = useBalance(); + } = useBalanceContext(); + const { storeState } = useStore(); const { diff --git a/frontend/components/MainPage/header/index.tsx b/frontend/components/MainPage/header/index.tsx index 786af663c..ad87a6564 100644 --- a/frontend/components/MainPage/header/index.tsx +++ b/frontend/components/MainPage/header/index.tsx @@ -2,7 +2,7 @@ import { Flex } from 'antd'; import { useCallback, useEffect, useState } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; @@ -12,7 +12,7 @@ import { AgentButton } from './AgentButton/AgentButton'; import { AgentHead } from './AgentHead'; const useSetupTrayIcon = () => { - const { isLowBalance } = useBalance(); + const { lowBalances } = useBalanceContext(); const { selectedService } = useServices(); const { deploymentStatus } = useService({ serviceConfigId: selectedService?.service_config_id, diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index f078e7679..e3282fb1a 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -4,7 +4,7 @@ import { useEffect } from 'react'; import { Pages } from '@/enums/Pages'; // import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; // import { useMasterSafe } from '@/hooks/useMasterSafe'; import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; @@ -33,7 +33,7 @@ export const Main = () => { updateBalances, isLoaded: isBalanceLoaded, setIsLoaded: setIsBalanceLoaded, - } = useBalance(); + } = useBalanceContext(); const { activeStakingProgramId, defaultStakingProgramId } = useStakingProgram(); @@ -60,7 +60,7 @@ export const Main = () => { ]); const hideMainOlasBalanceTopBorder = [ - !backupSafeAddress, + !backupSafeAddress, // TODO: update this condition to check backup safe relative to selectedService activeStakingProgramId === StakingProgramId.Alpha, isAllStakingContractDetailsRecordLoaded && !hasEnoughServiceSlots, ].some((condition) => !!condition); diff --git a/frontend/components/MainPage/sections/AlertSections/LowTradingBalanceAlert.tsx b/frontend/components/MainPage/sections/AlertSections/LowTradingBalanceAlert.tsx index 7b808eb64..43a13322e 100644 --- a/frontend/components/MainPage/sections/AlertSections/LowTradingBalanceAlert.tsx +++ b/frontend/components/MainPage/sections/AlertSections/LowTradingBalanceAlert.tsx @@ -2,13 +2,13 @@ import { Flex, Typography } from 'antd'; import { CustomAlert } from '@/components/Alert'; import { LOW_MASTER_SAFE_BALANCE } from '@/constants/thresholds'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useStore } from '@/hooks/useStore'; const { Text, Title } = Typography; export const LowTradingBalanceAlert = () => { - const { isBalanceLoaded, isLowBalance } = useBalance(); + const { isBalanceLoaded, isLowBalance } = useBalanceContext(); const { storeState } = useStore(); if (!isBalanceLoaded) return null; diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index 9e34670b7..8c5657d43 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -7,7 +7,7 @@ import styled from 'styled-components'; import { MiddlewareChain } from '@/client'; import { COLOR } from '@/constants/colors'; import { EXPLORER_URL } from '@/constants/urls'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useStore } from '@/hooks/useStore'; import { useWallet } from '@/hooks/useWallet'; @@ -36,7 +36,7 @@ const FineDot = styled(Dot)` `; const BalanceStatus = () => { - const { isBalanceLoaded, isLowBalance } = useBalance(); + const { isBalanceLoaded, isLowBalance } = useBalanceContext(); const { storeState } = useStore(); const { showNotification } = useElectronApi(); @@ -98,7 +98,7 @@ const TooltipContent = styled.div` export const GasBalanceSection = () => { const { masterSafeAddress } = useWallet(); - const { isBalanceLoaded } = useBalance(); + const { isBalanceLoaded } = useBalanceContext(); return ( { - const { isBalanceLoaded, totalOlasBalance } = useBalance(); + const { isBalanceLoaded, totalOlasBalance } = useBalanceContext(); // const { goto } = usePageState(); const balance = useMemo(() => { diff --git a/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx b/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx index 44549b816..d0662478e 100644 --- a/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx @@ -2,7 +2,7 @@ import { Button, Flex, Modal, Typography } from 'antd'; import Image from 'next/image'; import { useCallback, useEffect, useRef, useState } from 'react'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useReward } from '@/hooks/useReward'; import { useStore } from '@/hooks/useStore'; @@ -20,7 +20,7 @@ const OPERATE_URL = 'https://olas.network/operate?pearl=first-reward'; export const NotifyRewardsModal = () => { const { isEligibleForRewards, availableRewardsForEpochEth } = useReward(); - const { totalOlasBalance } = useBalance(); + const { totalOlasBalance } = useBalanceContext(); const { showNotification, store } = useElectronApi(); const { storeState } = useStore(); diff --git a/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx b/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx index e29be30dd..7e915eddb 100644 --- a/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx @@ -7,7 +7,7 @@ import { FireStreak } from '@/components/custom-icons/FireStreak'; import { COLOR } from '@/constants/colors'; import { NA } from '@/constants/symbols'; import { Pages } from '@/enums/PageState'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { usePageState } from '@/hooks/usePageState'; import { useReward } from '@/hooks/useReward'; import { useRewardsHistory } from '@/hooks/useRewardsHistory'; @@ -22,7 +22,7 @@ const RewardsStreakFlex = styled(Flex)` `; const Streak = () => { - const { isBalanceLoaded } = useBalance(); + const { isBalanceLoaded } = useBalanceContext(); const { isEligibleForRewards } = useReward(); const { latestRewardStreak: streak, diff --git a/frontend/components/MainPage/sections/RewardsSection/index.tsx b/frontend/components/MainPage/sections/RewardsSection/index.tsx index 8796767fe..2ec1ee1bf 100644 --- a/frontend/components/MainPage/sections/RewardsSection/index.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/index.tsx @@ -1,6 +1,6 @@ import { Flex, Skeleton, Tag, Typography } from 'antd'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useReward } from '@/hooks/useReward'; import { balanceFormat } from '@/utils/numberFormatters'; @@ -23,7 +23,7 @@ const getFormattedReward = (reward: number | undefined) => const DisplayRewards = () => { const { availableRewardsForEpochEth, isEligibleForRewards } = useReward(); - const { isBalanceLoaded } = useBalance(); + const { isBalanceLoaded } = useBalanceContext(); const reward = getFormattedReward(availableRewardsForEpochEth); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx index a045fc851..e0ded6024 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx @@ -4,7 +4,7 @@ import { isNil } from 'lodash'; import { CustomAlert } from '@/components/Alert'; import { LOW_MASTER_SAFE_BALANCE } from '@/constants/thresholds'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { @@ -27,7 +27,7 @@ const AlertInsufficientMigrationFunds = ({ useStakingContractContext(); const { isServiceStaked } = useActiveStakingContractInfo(); const { masterSafeBalance: safeBalance, totalOlasStakedBalance } = - useBalance(); + useBalanceContext(); const { serviceFundRequirements, isInitialFunded } = useNeedsFunds(); const totalOlasRequiredForStaking = getMinimumStakedAmountRequired( diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index bb63f7acc..6f2f53132 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -5,7 +5,7 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { Pages } from '@/enums/Pages'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useModals } from '@/hooks/useModals'; import { usePageState } from '@/hooks/usePageState'; import { useService } from '@/hooks/useService'; @@ -41,7 +41,7 @@ export const MigrateButton = ({ : '', }); - const { setIsPaused: setIsBalancePollingPaused } = useBalance(); + const { setIsPaused: setIsBalancePollingPaused } = useBalanceContext(); const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded } = useActiveStakingContractInfo(); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index 783f87ceb..7b859adf3 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -3,7 +3,7 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; import { useServices } from '@/hooks/useServices'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; @@ -46,7 +46,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { masterSafeBalance: safeBalance, totalOlasStakedBalance, isLowBalance, - } = useBalance(); + } = useBalanceContext(); const { activeStakingProgramId, activeStakingProgramMeta } = useStakingProgram(); const { needsInitialFunding } = useNeedsFunds(); diff --git a/frontend/components/SettingsPage/AddBackupWalletPage.tsx b/frontend/components/SettingsPage/AddBackupWalletPage.tsx index 6bcea847f..29271cb59 100644 --- a/frontend/components/SettingsPage/AddBackupWalletPage.tsx +++ b/frontend/components/SettingsPage/AddBackupWalletPage.tsx @@ -5,14 +5,14 @@ import { useMemo } from 'react'; import { MiddlewareChain } from '@/client'; import { MIN_ETH_BALANCE_THRESHOLDS } from '@/constants/thresholds'; import { SettingsScreen } from '@/enums/SettingsScreen'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useSettings } from '@/hooks/useSettings'; import { CardTitle } from '../Card/CardTitle'; import { CardFlex } from '../styled/CardFlex'; export const AddBackupWalletPage = () => { - const { masterEoaBalance: eoaBalance } = useBalance(); + const { masterEoaBalance: eoaBalance } = useBalanceContext(); const { goto } = useSettings(); const [form] = Form.useForm(); diff --git a/frontend/components/SettingsPage/DebugInfoSection.tsx b/frontend/components/SettingsPage/DebugInfoSection.tsx index e8b3dfee7..31b0cc7d4 100644 --- a/frontend/components/SettingsPage/DebugInfoSection.tsx +++ b/frontend/components/SettingsPage/DebugInfoSection.tsx @@ -19,7 +19,7 @@ import { EXPLORER_URL } from '@/constants/urls'; import { MODAL_WIDTH } from '@/constants/width'; import { TokenSymbol } from '@/enums/Token'; import { useAddress } from '@/hooks/useAddress'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useWallet } from '@/hooks/useWallet'; import { WalletAddressNumberRecord } from '@/types/Records'; import { copyToClipboard } from '@/utils/copyToClipboard'; @@ -119,7 +119,7 @@ const DebugItem = ({ export const DebugInfoSection = () => { const { wallets, masterEoaAddress, masterSafeAddress } = useWallet(); const { instanceAddress, multisigAddress } = useAddress(); - const { walletBalances } = useBalance(); + const { walletBalances } = useBalanceContext(); const [isModalOpen, setIsModalOpen] = useState(false); const showModal = useCallback(() => setIsModalOpen(true), []); diff --git a/frontend/components/SetupPage/SetupWelcome.tsx b/frontend/components/SetupPage/SetupWelcome.tsx index 7cd2f0146..acf4bef59 100644 --- a/frontend/components/SetupPage/SetupWelcome.tsx +++ b/frontend/components/SetupPage/SetupWelcome.tsx @@ -14,7 +14,7 @@ import { useCallback, useEffect, useMemo, useState } from 'react'; import { MiddlewareAccountIsSetup } from '@/client'; import { Pages } from '@/enums/Pages'; import { SetupScreen } from '@/enums/SetupScreen'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { usePageState } from '@/hooks/usePageState'; import { useSetup } from '@/hooks/useSetup'; @@ -130,7 +130,7 @@ export const SetupWelcomeLogin = () => { const { goto: gotoPage } = usePageState(); const { masterSafeAddress, wallets } = useWallet(); - const { isBalanceLoaded, masterEoaBalance: eoaBalance } = useBalance(); + const { isBalanceLoaded, masterEoaBalance: eoaBalance } = useBalanceContext(); const [isLoggingIn, setIsLoggingIn] = useState(false); const [canNavigate, setCanNavigate] = useState(false); diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index 8155d6bd2..efcd88498 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -7,7 +7,7 @@ import { MiddlewareChain } from '@/client'; import { SERVICE_REGISTRY_L2_CONTRACT_ADDRESS } from '@/config/olasContracts'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { useAddress } from '@/hooks/useAddress'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useReward } from '@/hooks/useReward'; import { useServices } from '@/hooks/useServices'; import { generateName } from '@/utils/agentName'; @@ -149,7 +149,7 @@ const ServiceAndNftDetails = () => { }; export const YourAgentWallet = () => { - const { isBalanceLoaded, agentSafeBalance, agentEoaBalance } = useBalance(); + const { isBalanceLoaded, agentSafeBalance, agentEoaBalance } = useBalanceContext(); const { availableRewardsForEpochEth, isEligibleForRewards, diff --git a/frontend/components/YourWalletPage/index.tsx b/frontend/components/YourWalletPage/index.tsx index 0968ad88e..e2486f04b 100644 --- a/frontend/components/YourWalletPage/index.tsx +++ b/frontend/components/YourWalletPage/index.tsx @@ -7,7 +7,7 @@ import { CardTitle } from '@/components/Card/CardTitle'; import { InfoBreakdownList } from '@/components/InfoBreakdown'; import { CardFlex } from '@/components/styled/CardFlex'; import { Pages } from '@/enums/Pages'; -import { useBalance } from '@/hooks/useBalance'; +import { useBalanceContext } from '@/hooks/useBalanceContext'; import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; import { useWallet } from '@/hooks/useWallet'; @@ -49,7 +49,7 @@ const Address = () => { const OlasBalance = () => { const { masterSafeBalance: safeBalance, totalOlasStakedBalance } = - useBalance(); + useBalanceContext(); const olasBalances = useMemo(() => { return [ { @@ -79,7 +79,7 @@ const OlasBalance = () => { }; const XdaiBalance = () => { - const { masterSafeBalance: safeBalance } = useBalance(); + const { masterSafeBalance: safeBalance } = useBalanceContext(); return ( @@ -99,7 +99,7 @@ const XdaiBalance = () => { const Signer = () => { const { masterEoaAddress } = useWallet(); - const { masterEoaBalance: eoaBalance } = useBalance(); + const { masterEoaBalance: eoaBalance } = useBalanceContext(); return ( diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 8b4119a1a..46645dfca 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -33,6 +33,13 @@ import { formatEther } from '@/utils/numberFormatters'; import { OnlineStatusContext } from './OnlineStatusProvider'; import { WalletContext } from './WalletProvider'; +type CrossChainStakedBalances = Array<{ + serviceId: string; + chainId: number; + olasBondBalance: number; + olasDepositBalance: number; +}>; + export const BalanceContext = createContext<{ isLoaded: boolean; setIsLoaded: Dispatch>; @@ -58,7 +65,7 @@ export const BalanceContext = createContext<{ isPaused: false, setIsPaused: () => {}, walletBalances: [], - stakedBalances: {}, + stakedBalances: [], totalOlasBalance: 0, totalEthBalance: 0, totalStakedOlasBalance: 0, @@ -78,7 +85,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { [], ); const [stakedBalances, setStakedBalances] = - useState({}); + useState([]); const totalEthBalance = useMemo(() => { if (!isLoaded) return 0; @@ -101,21 +108,11 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { }, [isLoaded, walletBalances]); const totalStakedOlasBalance = useMemo(() => { - return Object.values(stakedBalances).reduce( - (serviceAcc, serviceBalances) => { - return ( - serviceAcc + - Object.values(serviceBalances).reduce((chainAcc, chainBalance) => { - return ( - chainAcc + - (chainBalance.olasBondBalance || 0) + - (chainBalance.olasDepositBalance || 0) - ); - }, 0) - ); - }, - 0, - ); + return stakedBalances.reduce((acc, balance) => { + return ( + acc + (balance.olasBondBalance || 0) + (balance.olasDepositBalance || 0) + ); + }, 0); }, [stakedBalances]); /** @@ -135,25 +132,29 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { for (const service of services) { const serviceId = service.service_config_id; const serviceHomeChainId = service.home_chain_id; - const serviceStakedBalances = stakedBalances[serviceId]; - if (!serviceStakedBalances) continue; + + const stakedBalancesForService = stakedBalances.filter( + (balance) => + balance.serviceId === serviceId && + balance.chainId === serviceHomeChainId, + ); + + if (stakedBalancesForService.length === 0) continue; // Get addresses for master safe and agent home chain safe const masterSafeWallet = wallets.find( (wallet) => wallet.owner === WalletOwnerType.Master && wallet.type === WalletType.Safe && - wallet.chainId === service.home_chain_id, + wallet.chainId === serviceHomeChainId, ); const masterSafeAddress = masterSafeWallet?.address; const stakedAgentSafeAddress = service.chain_configs[serviceHomeChainId]?.chain_data.multisig; - // Skip invalid service if (!masterSafeAddress && !stakedAgentSafeAddress) continue; - // Balances const masterSafeBalanceResult = walletBalances.find( (balance) => balance.walletAddress === masterSafeAddress && balance.isNative, @@ -166,27 +167,27 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { if ( masterSafeBalanceResult && - masterSafeBalanceResult.balance < LOW_MASTER_SAFE_BALANCE // TODO: use agent specific threshold + masterSafeBalanceResult.balance < LOW_MASTER_SAFE_BALANCE ) { result.push({ serviceConfigId: service.service_config_id, chainId: serviceHomeChainId, walletAddress: masterSafeBalanceResult.walletAddress, balance: masterSafeBalanceResult.balance, - expectedBalance: LOW_MASTER_SAFE_BALANCE, // TODO: use agent specific threshold + expectedBalance: LOW_MASTER_SAFE_BALANCE, }); } if ( stakedAgentSafeBalanceResult && - stakedAgentSafeBalanceResult.balance < LOW_AGENT_SAFE_BALANCE // TODO: use agent specific threshold + stakedAgentSafeBalanceResult.balance < LOW_AGENT_SAFE_BALANCE ) { result.push({ serviceConfigId: service.service_config_id, chainId: serviceHomeChainId, walletAddress: stakedAgentSafeBalanceResult.walletAddress, balance: stakedAgentSafeBalanceResult.balance, - expectedBalance: LOW_AGENT_SAFE_BALANCE, // TODO: use agent specific threshold + expectedBalance: LOW_AGENT_SAFE_BALANCE, }); } } @@ -325,19 +326,10 @@ const getCrossChainWalletBalances = async ( return balanceResults; }; -type CrossChainStakedBalances = { - [serviceId: string]: { - [chainId: number]: { - olasBondBalance: number; - olasDepositBalance: number; - }; - }; -}; - const getCrossChainStakedBalances = async ( services: MiddlewareServiceResponse[], ): Promise => { - const result: CrossChainStakedBalances = {}; + const result: CrossChainStakedBalances = []; const registryInfoPromises = services.map(async (service) => { const serviceId = service.service_config_id; @@ -346,13 +338,7 @@ const getCrossChainStakedBalances = async ( const { multisig, token } = homeChainConfig.chain_data; if (!multisig || !token) { - return { - serviceId, - homeChainId, - depositValue: 0, - bondValue: 0, - serviceState: ServiceRegistryL2ServiceState.NonExistent, - }; + return null; } const registryInfo = await StakedAgentService.getServiceRegistryInfo( @@ -363,29 +349,32 @@ const getCrossChainStakedBalances = async ( return { serviceId, - homeChainId, + chainId: homeChainId, ...registryInfo, }; }); - // TODO: chunk and batch multicalls by chain, - // currently Promise is returned by `StakedAgentService.getServiceRegistryInfo` - // will not scale well with large number of services const registryInfos = await Promise.allSettled(registryInfoPromises); - registryInfos.forEach((res) => { - if (res.status === 'fulfilled') { - const { serviceId, homeChainId, depositValue, bondValue, serviceState } = + registryInfos.forEach((res, idx) => { + if (res.status === 'fulfilled' && res.value) { + const { serviceId, chainId, depositValue, bondValue, serviceState } = res.value; - if (!result[serviceId]) result[serviceId] = {}; - result[serviceId][homeChainId] = correctBondDepositByServiceState({ - olasBondBalance: bondValue, - olasDepositBalance: depositValue, - serviceState, + result.push({ + serviceId, + chainId, + ...correctBondDepositByServiceState({ + olasBondBalance: bondValue, + olasDepositBalance: depositValue, + serviceState, + }), }); } else { - console.error('Error fetching registry info:', res.reason); + console.error( + 'Error fetching registry info for', + services[idx].service_config_id, + ); } }); diff --git a/frontend/hooks/useBalance.ts b/frontend/hooks/useBalance.ts deleted file mode 100644 index c8d21df91..000000000 --- a/frontend/hooks/useBalance.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { useContext } from 'react'; - -import { BalanceContext } from '@/context/BalanceProvider'; - -export const useBalance = () => useContext(BalanceContext); diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts new file mode 100644 index 000000000..cd96ec932 --- /dev/null +++ b/frontend/hooks/useBalanceContext.ts @@ -0,0 +1,35 @@ +import { useContext, useMemo } from 'react'; + +import { BalanceContext } from '@/context/BalanceProvider'; + +import { useService } from './useService'; + +export const useBalanceContext = () => useContext(BalanceContext); + +export const useServiceBalances = (serviceConfigId: string) => { + const { flatAddresses } = useService({ serviceConfigId }); + const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); + + const serviceWalletBalances = useMemo( + () => + walletBalances?.filter((balance) => + flatAddresses.includes(balance.walletAddress), + ), + [flatAddresses, walletBalances], + ); + + const serviceStakedBalances = useMemo( + () => + stakedBalances?.filter((balance) => + flatAddresses.includes(balance.walletAddress), + ), + [flatAddresses, stakedBalances], + ); + + const serviceLowBalances = useMemo( + () => lowBalances?.filter((balance) => balance.walletAddress), + [lowBalances], + ); + + return { serviceWalletBalances, serviceLowBalances }; +}; diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index de88bb930..fd0a3d407 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -3,7 +3,7 @@ import { useMemo } from 'react'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; -import { useBalance } from './useBalance'; +import { useBalanceContext } from './useBalanceContext'; import { useMasterSafe } from './useMasterSafe'; import { useServices } from './useServices'; import { useStore } from './useStore'; @@ -33,7 +33,7 @@ const useBalancesLogs = () => { wallets, walletBalances, totalOlasStakedBalance, - } = useBalance(); + } = useBalanceContext(); return { isLoaded: isBalanceLoaded, diff --git a/frontend/hooks/useNeedsFunds.ts b/frontend/hooks/useNeedsFunds.ts index 6898ea776..bbe4931dd 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -3,7 +3,7 @@ import { useMemo } from 'react'; import { CHAIN_CONFIG } from '@/config/chains'; -import { useBalance } from './useBalance'; +import { useBalanceContext } from './useBalanceContext'; import { useServiceTemplates } from './useServiceTemplates'; import { useStore } from './useStore'; @@ -22,7 +22,7 @@ export const useNeedsFunds = () => { isBalanceLoaded, masterSafeBalance: safeBalance, totalOlasStakedBalance, - } = useBalance(); + } = useBalanceContext(); const serviceFundRequirements = useMemo(() => { const gasEstimate = diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index c3f71d69a..ee09879a3 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -58,6 +58,14 @@ export const useService = ({ return addressesByChainId; }, [service]); + const flatAddresses = useMemo(() => { + return Object.values(addresses).reduce((acc, { agentSafe, agentEoas }) => { + if (agentSafe) acc.push(agentSafe); + if (agentEoas) acc.push(...agentEoas); + return acc; + }, [] as Address[]); + }, [addresses]); + /** * Overrides the deployment status of the service in the cache. * @note Overwrite is only temporary if ServicesContext is polling @@ -75,6 +83,7 @@ export const useService = ({ return { service, addresses, + flatAddresses, isLoaded, deploymentStatus, setDeploymentStatus, From 79d391f2f3532f15b9b0c0fe6a89f1cd6e31df4f Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 11:26:22 +0000 Subject: [PATCH 250/463] refactor: make staked wallet balances an array, object is annoying --- frontend/context/BalanceProvider.tsx | 101 ++++++++++++--------------- 1 file changed, 45 insertions(+), 56 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 8b4119a1a..46645dfca 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -33,6 +33,13 @@ import { formatEther } from '@/utils/numberFormatters'; import { OnlineStatusContext } from './OnlineStatusProvider'; import { WalletContext } from './WalletProvider'; +type CrossChainStakedBalances = Array<{ + serviceId: string; + chainId: number; + olasBondBalance: number; + olasDepositBalance: number; +}>; + export const BalanceContext = createContext<{ isLoaded: boolean; setIsLoaded: Dispatch>; @@ -58,7 +65,7 @@ export const BalanceContext = createContext<{ isPaused: false, setIsPaused: () => {}, walletBalances: [], - stakedBalances: {}, + stakedBalances: [], totalOlasBalance: 0, totalEthBalance: 0, totalStakedOlasBalance: 0, @@ -78,7 +85,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { [], ); const [stakedBalances, setStakedBalances] = - useState({}); + useState([]); const totalEthBalance = useMemo(() => { if (!isLoaded) return 0; @@ -101,21 +108,11 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { }, [isLoaded, walletBalances]); const totalStakedOlasBalance = useMemo(() => { - return Object.values(stakedBalances).reduce( - (serviceAcc, serviceBalances) => { - return ( - serviceAcc + - Object.values(serviceBalances).reduce((chainAcc, chainBalance) => { - return ( - chainAcc + - (chainBalance.olasBondBalance || 0) + - (chainBalance.olasDepositBalance || 0) - ); - }, 0) - ); - }, - 0, - ); + return stakedBalances.reduce((acc, balance) => { + return ( + acc + (balance.olasBondBalance || 0) + (balance.olasDepositBalance || 0) + ); + }, 0); }, [stakedBalances]); /** @@ -135,25 +132,29 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { for (const service of services) { const serviceId = service.service_config_id; const serviceHomeChainId = service.home_chain_id; - const serviceStakedBalances = stakedBalances[serviceId]; - if (!serviceStakedBalances) continue; + + const stakedBalancesForService = stakedBalances.filter( + (balance) => + balance.serviceId === serviceId && + balance.chainId === serviceHomeChainId, + ); + + if (stakedBalancesForService.length === 0) continue; // Get addresses for master safe and agent home chain safe const masterSafeWallet = wallets.find( (wallet) => wallet.owner === WalletOwnerType.Master && wallet.type === WalletType.Safe && - wallet.chainId === service.home_chain_id, + wallet.chainId === serviceHomeChainId, ); const masterSafeAddress = masterSafeWallet?.address; const stakedAgentSafeAddress = service.chain_configs[serviceHomeChainId]?.chain_data.multisig; - // Skip invalid service if (!masterSafeAddress && !stakedAgentSafeAddress) continue; - // Balances const masterSafeBalanceResult = walletBalances.find( (balance) => balance.walletAddress === masterSafeAddress && balance.isNative, @@ -166,27 +167,27 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { if ( masterSafeBalanceResult && - masterSafeBalanceResult.balance < LOW_MASTER_SAFE_BALANCE // TODO: use agent specific threshold + masterSafeBalanceResult.balance < LOW_MASTER_SAFE_BALANCE ) { result.push({ serviceConfigId: service.service_config_id, chainId: serviceHomeChainId, walletAddress: masterSafeBalanceResult.walletAddress, balance: masterSafeBalanceResult.balance, - expectedBalance: LOW_MASTER_SAFE_BALANCE, // TODO: use agent specific threshold + expectedBalance: LOW_MASTER_SAFE_BALANCE, }); } if ( stakedAgentSafeBalanceResult && - stakedAgentSafeBalanceResult.balance < LOW_AGENT_SAFE_BALANCE // TODO: use agent specific threshold + stakedAgentSafeBalanceResult.balance < LOW_AGENT_SAFE_BALANCE ) { result.push({ serviceConfigId: service.service_config_id, chainId: serviceHomeChainId, walletAddress: stakedAgentSafeBalanceResult.walletAddress, balance: stakedAgentSafeBalanceResult.balance, - expectedBalance: LOW_AGENT_SAFE_BALANCE, // TODO: use agent specific threshold + expectedBalance: LOW_AGENT_SAFE_BALANCE, }); } } @@ -325,19 +326,10 @@ const getCrossChainWalletBalances = async ( return balanceResults; }; -type CrossChainStakedBalances = { - [serviceId: string]: { - [chainId: number]: { - olasBondBalance: number; - olasDepositBalance: number; - }; - }; -}; - const getCrossChainStakedBalances = async ( services: MiddlewareServiceResponse[], ): Promise => { - const result: CrossChainStakedBalances = {}; + const result: CrossChainStakedBalances = []; const registryInfoPromises = services.map(async (service) => { const serviceId = service.service_config_id; @@ -346,13 +338,7 @@ const getCrossChainStakedBalances = async ( const { multisig, token } = homeChainConfig.chain_data; if (!multisig || !token) { - return { - serviceId, - homeChainId, - depositValue: 0, - bondValue: 0, - serviceState: ServiceRegistryL2ServiceState.NonExistent, - }; + return null; } const registryInfo = await StakedAgentService.getServiceRegistryInfo( @@ -363,29 +349,32 @@ const getCrossChainStakedBalances = async ( return { serviceId, - homeChainId, + chainId: homeChainId, ...registryInfo, }; }); - // TODO: chunk and batch multicalls by chain, - // currently Promise is returned by `StakedAgentService.getServiceRegistryInfo` - // will not scale well with large number of services const registryInfos = await Promise.allSettled(registryInfoPromises); - registryInfos.forEach((res) => { - if (res.status === 'fulfilled') { - const { serviceId, homeChainId, depositValue, bondValue, serviceState } = + registryInfos.forEach((res, idx) => { + if (res.status === 'fulfilled' && res.value) { + const { serviceId, chainId, depositValue, bondValue, serviceState } = res.value; - if (!result[serviceId]) result[serviceId] = {}; - result[serviceId][homeChainId] = correctBondDepositByServiceState({ - olasBondBalance: bondValue, - olasDepositBalance: depositValue, - serviceState, + result.push({ + serviceId, + chainId, + ...correctBondDepositByServiceState({ + olasBondBalance: bondValue, + olasDepositBalance: depositValue, + serviceState, + }), }); } else { - console.error('Error fetching registry info:', res.reason); + console.error( + 'Error fetching registry info for', + services[idx].service_config_id, + ); } }); From 733759e3c94b26f616aa01f50bc1495246678a8e Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 11:30:14 +0000 Subject: [PATCH 251/463] fix: fallback to default staking program id --- frontend/components/MainPage/index.tsx | 7 +++---- frontend/context/StakingProgramProvider.tsx | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index e3282fb1a..de795bcc4 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -28,20 +28,19 @@ import { RewardsSection } from './sections/RewardsSection'; export const Main = () => { const { goto } = usePageState(); // const { backupSafeAddress } = useMasterSafe(); - const { updateServicesState } = useServices(); + const { refetch: updateServicesState } = useServices(); const { updateBalances, isLoaded: isBalanceLoaded, setIsLoaded: setIsBalanceLoaded, } = useBalanceContext(); - const { activeStakingProgramId, defaultStakingProgramId } = - useStakingProgram(); + const { activeStakingProgramId } = useStakingProgram(); const { isAllStakingContractDetailsRecordLoaded } = useStakingContractContext(); const { hasEnoughServiceSlots } = useStakingContractDetails( - activeStakingProgramId ?? defaultStakingProgramId, + activeStakingProgramId ?? INITIAL_DEFAULT_STAKING_PROGRAM_ID, ); /** diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index 3e6685747..3013d7467 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -1,5 +1,4 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; -import { Maybe } from 'graphql/jsutils/Maybe'; import { createContext, PropsWithChildren, useCallback } from 'react'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; @@ -13,10 +12,10 @@ const INITIAL_DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.PearlBeta; export const StakingProgramContext = createContext<{ isActiveStakingProgramLoaded: boolean; - activeStakingProgramId: Maybe; + activeStakingProgramId: StakingProgramId; }>({ isActiveStakingProgramLoaded: false, - activeStakingProgramId: null, + activeStakingProgramId: INITIAL_DEFAULT_STAKING_PROGRAM_ID, }); /** @@ -73,7 +72,8 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { value={{ isActiveStakingProgramLoaded: !isStakingProgramsLoading && !!activeStakingProgramId, - activeStakingProgramId, + activeStakingProgramId: + activeStakingProgramId || INITIAL_DEFAULT_STAKING_PROGRAM_ID, }} > {children} From b5894b73847dd73d25313a7be2e04c2fb53ce657 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 11:32:24 +0000 Subject: [PATCH 252/463] chore: comment non-critical func --- frontend/components/MainPage/index.tsx | 72 ++++++++++++-------------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index de795bcc4..f1d3bc8d7 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -1,18 +1,10 @@ import { QuestionCircleOutlined, SettingOutlined } from '@ant-design/icons'; import { Button, Card, Flex } from 'antd'; -import { useEffect } from 'react'; import { Pages } from '@/enums/Pages'; // import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; // import { useMasterSafe } from '@/hooks/useMasterSafe'; import { usePageState } from '@/hooks/usePageState'; -import { useServices } from '@/hooks/useServices'; -import { - useStakingContractContext, - useStakingContractDetails, -} from '@/hooks/useStakingContractDetails'; -import { useStakingProgram } from '@/hooks/useStakingProgram'; // import { useStakingProgram } from '@/hooks/useStakingProgram'; import { MainHeader } from './header'; @@ -28,41 +20,43 @@ import { RewardsSection } from './sections/RewardsSection'; export const Main = () => { const { goto } = usePageState(); // const { backupSafeAddress } = useMasterSafe(); - const { refetch: updateServicesState } = useServices(); - const { - updateBalances, - isLoaded: isBalanceLoaded, - setIsLoaded: setIsBalanceLoaded, - } = useBalanceContext(); - const { activeStakingProgramId } = useStakingProgram(); + // const { refetch: updateServicesState } = useServices(); + // const { + // updateBalances, + // isLoaded: isBalanceLoaded, + // setIsLoaded: setIsBalanceLoaded, + // } = useBalanceContext(); + // const { activeStakingProgramId } = useStakingProgram(); - const { isAllStakingContractDetailsRecordLoaded } = - useStakingContractContext(); + // TODO: reintroduce later, non critical + // const { isAllStakingContractDetailsRecordLoaded } = + // useStakingContractContext(); - const { hasEnoughServiceSlots } = useStakingContractDetails( - activeStakingProgramId ?? INITIAL_DEFAULT_STAKING_PROGRAM_ID, - ); + // const { hasEnoughServiceSlots } = useStakingContractDetails( + // activeStakingProgramId, + // ); + + // TODO: reintroduce later, non critical + + // useEffect(() => { + // if (!isBalanceLoaded) { + // updateServicesState?.().then(() => updateBalances()); + // setIsBalanceLoaded(true); + // } + // }, [ + // isBalanceLoaded, + // setIsBalanceLoaded, + // updateBalances, + // updateServicesState, + // ]); - /** - * @todo fix this isLoaded logic - */ - useEffect(() => { - if (!isBalanceLoaded) { - updateServicesState().then(() => updateBalances()); - setIsBalanceLoaded(true); - } - }, [ - isBalanceLoaded, - setIsBalanceLoaded, - updateBalances, - updateServicesState, - ]); + // TODO: reintroduce later, non critical - const hideMainOlasBalanceTopBorder = [ - !backupSafeAddress, // TODO: update this condition to check backup safe relative to selectedService - activeStakingProgramId === StakingProgramId.Alpha, - isAllStakingContractDetailsRecordLoaded && !hasEnoughServiceSlots, - ].some((condition) => !!condition); + // const hideMainOlasBalanceTopBorder = [ + // !backupSafeAddress, // TODO: update this condition to check backup safe relative to selectedService + // activeStakingProgramId === StakingProgramId.Alpha, + // isAllStakingContractDetailsRecordLoaded && !hasEnoughServiceSlots, + // ].some((condition) => !!condition); return ( Date: Wed, 20 Nov 2024 11:51:52 +0000 Subject: [PATCH 253/463] refactor: rename parameter in getServiceTemplate for clarity --- frontend/hooks/useServiceTemplates.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/frontend/hooks/useServiceTemplates.ts b/frontend/hooks/useServiceTemplates.ts index 0a6e39d88..a3532ddb6 100644 --- a/frontend/hooks/useServiceTemplates.ts +++ b/frontend/hooks/useServiceTemplates.ts @@ -4,11 +4,9 @@ import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; export const useServiceTemplates = () => { const getServiceTemplates = (): ServiceTemplate[] => SERVICE_TEMPLATES; const getServiceTemplate = ( - serviceUuid: string, + templateHash: string, ): ServiceTemplate | undefined => - SERVICE_TEMPLATES.find( - (template) => template.service_config_id === serviceUuid, - ); + SERVICE_TEMPLATES.find((template) => template.hash === templateHash); return { getServiceTemplate, From ef21c58d28491d3a4500985091ab2d8b4c84e279 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 11:54:32 +0000 Subject: [PATCH 254/463] feat: enhance useServiceBalances to include safe balances and low balance indicator --- frontend/hooks/useBalanceContext.ts | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index cd96ec932..1fb72c3bd 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -1,6 +1,6 @@ import { useContext, useMemo } from 'react'; -import { BalanceContext } from '@/context/BalanceProvider'; +import { BalanceContext, WalletBalanceResult } from '@/context/BalanceProvider'; import { useService } from './useService'; @@ -31,5 +31,24 @@ export const useServiceBalances = (serviceConfigId: string) => { [lowBalances], ); - return { serviceWalletBalances, serviceLowBalances }; + const isLowBalance = useMemo( + () => serviceLowBalances?.length > 0, + [serviceLowBalances], + ); + + const serviceSafeBalances = useMemo( + () => + walletBalances?.filter((balance) => + flatAddresses.includes(balance.walletAddress), + ), + [flatAddresses, walletBalances], + ); + + return { + serviceWalletBalances, + serviceStakedBalances, + serviceSafeBalances, + serviceLowBalances, + isLowBalance, + }; }; From 24594d8e44e403edec19b9ae12150982e0299b82 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 11:54:43 +0000 Subject: [PATCH 255/463] feat: add walletAddress to CrossChainStakedBalances and WalletBalanceResult types --- frontend/context/BalanceProvider.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 46645dfca..2eb09d8e8 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -38,6 +38,7 @@ type CrossChainStakedBalances = Array<{ chainId: number; olasBondBalance: number; olasDepositBalance: number; + walletAddress: Address; }>; export const BalanceContext = createContext<{ @@ -250,7 +251,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { ); }; -type WalletBalanceResult = { +export type WalletBalanceResult = { walletAddress: Address; chainId: ChainId; symbol: TokenSymbol; @@ -369,6 +370,8 @@ const getCrossChainStakedBalances = async ( olasDepositBalance: depositValue, serviceState, }), + walletAddress: + services[idx].chain_configs[chainId].chain_data.multisig!, // multisig must exist if registry info is fetched }); } else { console.error( From 8ccf0fe84d7c4f2752968616457fc74ac70aefeb Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:03:55 +0000 Subject: [PATCH 256/463] refactor: simplify chain-specific configuration handling in createService --- frontend/service/Services.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/frontend/service/Services.ts b/frontend/service/Services.ts index a80189c77..4c90e3d81 100644 --- a/frontend/service/Services.ts +++ b/frontend/service/Services.ts @@ -53,13 +53,11 @@ const createService = async ({ serviceTemplate, stakingProgramId, useMechMarketplace = false, - chainId, }: { deploy: boolean; serviceTemplate: ServiceTemplate; stakingProgramId: StakingProgramId; useMechMarketplace?: boolean; - chainId: ChainId; }): Promise => fetch(`${BACKEND_URL_V2}/service`, { method: 'POST', @@ -67,12 +65,19 @@ const createService = async ({ ...serviceTemplate, deploy, configurations: { - [chainId]: { - ...serviceTemplate.configurations[ChainId.Optimism], - staking_program_id: stakingProgramId, - rpc: CHAIN_CONFIG[chainId].rpc, - use_mech_marketplace: useMechMarketplace, - }, + ...serviceTemplate.configurations, + // overwrite defaults with chain-specific configurations + ...Object.entries(serviceTemplate.configurations).reduce( + (acc, [chainId, config]) => { + acc[+chainId] = { + ...config, + rpc: CHAIN_CONFIG[+chainId].rpc, + staking_program_id: stakingProgramId, + use_mech_marketplace: useMechMarketplace, + }; + return acc; + }, + ), }, }), headers: { ...CONTENT_TYPE_JSON_UTF8 }, From c22806fb1a81e312985b847654eb748d47621883 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:04:07 +0000 Subject: [PATCH 257/463] fix: update staking program ID for Gnosis chain in service templates --- frontend/constants/serviceTemplates.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 8a781f0e9..9332dd195 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -12,8 +12,8 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ service_version: 'v0.18.4', home_chain_id: ChainId.Gnosis.toString(), configurations: { - [ChainId.Optimism]: { - staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten + [ChainId.Gnosis]: { + staking_program_id: StakingProgramId.PearlBeta, // default, may be overwritten nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', rpc: 'http://localhost:8545', agent_id: 14, From 897590644ce5aa697dfdbd8d11f8a891236939a6 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:05:17 +0000 Subject: [PATCH 258/463] feat: enhance AgentNotRunningButton to utilize service-specific balances and improve staking requirements handling --- .../AgentButton/AgentNotRunningButton.tsx | 74 ++++++++++--------- 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index b3957eda4..72bdc60e0 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -3,9 +3,12 @@ import { useCallback, useMemo } from 'react'; import { MiddlewareChain, MiddlewareDeploymentStatus } from '@/client'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; -import { ChainId } from '@/enums/Chain'; -import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { LOW_MASTER_SAFE_BALANCE } from '@/constants/thresholds'; +import { TokenSymbol } from '@/enums/Token'; +import { + useBalanceContext, + useServiceBalances, +} from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; @@ -23,45 +26,37 @@ import { WalletService } from '@/service/Wallet'; import { delayInSeconds } from '@/utils/delay'; /** Button used to start / deploy the agent */ -export const AgentNotRunningButton = () => { - const { wallets, masterSafeAddress } = useWallet(); - +export const AgentNotRunningButton = (serviceConfigId: string) => { + const { wallets } = useWallet(); const { selectedService, setPaused: setIsServicePollingPaused, isFetched: isLoaded, refetch: updateServicesState, } = useServices(); - const { service, deploymentStatus, setDeploymentStatus } = useService({ serviceConfigId: isLoaded && selectedService ? selectedService?.service_config_id : '', }); - const { serviceTemplate } = useServiceTemplates(); const { showNotification } = useElectronApi(); const { setIsPaused: setIsBalancePollingPaused, - masterSafeBalance: safeBalance, - isLowBalance, - totalOlasStakedBalance, + totalStakedOlasBalance, totalEthBalance, updateBalances, } = useBalanceContext(); - + const { serviceSafeBalances, isLowBalance } = + useServiceBalances(serviceConfigId); const { storeState } = useStore(); - const { isAllStakingContractDetailsRecordLoaded, setIsPaused: setIsStakingContractInfoPollingPaused, refetchActiveStakingContractDetails, } = useStakingContractContext(); - const { activeStakingProgramId } = useStakingProgram(); - const { isEligibleForStaking, isAgentEvicted, isServiceStaked } = useActiveStakingContractInfo(); - const { hasEnoughServiceSlots } = useStakingContractDetails( activeStakingProgramId, ); @@ -70,14 +65,19 @@ export const AgentNotRunningButton = () => { // allStakingContractDetailsRecord?.[activeStakingProgram ?? defaultStakingProgram] // ?.minStakingDeposit; - const requiredOlas = - STAKING_PROGRAMS[activeStakingProgramId]?.minStakingDeposit; // TODO: fix activeStakingProgramId + const requiredStakedOlas = + service && + STAKING_PROGRAMS[service.home_chain_id][activeStakingProgramId] + ?.stakingRequirements[TokenSymbol.OLAS]; // TODO: fix activeStakingProgramId + + const safeOlasBalance = serviceSafeBalances.find((walletBalanceResult) => { + return walletBalanceResult.symbol === TokenSymbol.OLAS; + })?.balance; - const safeOlasBalance = safeBalance?.OLAS; const safeOlasBalanceWithStaked = - safeOlasBalance === undefined || totalOlasStakedBalance === undefined + safeOlasBalance === undefined || totalStakedOlasBalance === undefined ? undefined - : safeOlasBalance + totalOlasStakedBalance; + : safeOlasBalance + totalStakedOlasBalance; const handleStart = useCallback(async () => { // Must have a wallet to start the agent @@ -95,17 +95,16 @@ export const AgentNotRunningButton = () => { // Mock "DEPLOYING" status (service polling will update this once resumed) setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYING); - // Get the active staking program id; default id if there's no agent yet - const stakingProgramId: StakingProgramId = activeStakingProgramId; - // Create master safe if it doesn't exist try { - if (!masterSafeAddress) { + if ( + !service?.chain_configs[service.home_chain_id]?.chain_data?.multisig + ) { await WalletService.createSafe(MiddlewareChain.OPTIMISM); } } catch (error) { console.error(error); - setServiceStatus(undefined); + // setServiceStatus(undefined); // TODO: reimplement state if it is missing showNotification?.('Some error occurred while creating safe'); setIsStakingContractInfoPollingPaused(false); setIsServicePollingPaused(false); @@ -116,17 +115,16 @@ export const AgentNotRunningButton = () => { // Then create / deploy the service try { await ServicesService.createService({ - activeStakingProgramId, + stakingProgramId: activeStakingProgramId, serviceTemplate, deploy: true, useMechMarketplace: false, - chainId: ChainId.Gnosis, // TODO: Add support for other chains }); - await ServicesService.startService(serviceTemplate.service_config_id); + await ServicesService.startService(serviceConfigId); } catch (error) { console.error(error); - setServiceStatus(undefined); + // setServiceStatus(undefined); TODO: reimplement state if it is missing showNotification?.('Some error occurred while deploying service'); setIsServicePollingPaused(false); setIsBalancePollingPaused(false); @@ -170,10 +168,12 @@ export const AgentNotRunningButton = () => { setIsBalancePollingPaused, setIsStakingContractInfoPollingPaused, setDeploymentStatus, - masterSafeAddress, + service?.chain_configs, + service?.home_chain_id, showNotification, activeStakingProgramId, serviceTemplate, + serviceConfigId, updateServicesState, refetchActiveStakingContractDetails, updateBalances, @@ -195,7 +195,7 @@ export const AgentNotRunningButton = () => { if (deploymentStatus === MiddlewareDeploymentStatus.DEPLOYING) return false; if (deploymentStatus === MiddlewareDeploymentStatus.STOPPING) return false; - if (!requiredOlas) return false; + if (!requiredStakedOlas) return false; // If no slots available, agent cannot be started if (!hasEnoughServiceSlots && !isServiceStaked) return false; @@ -204,21 +204,23 @@ export const AgentNotRunningButton = () => { if (service && storeState?.isInitialFunded) { if (!safeOlasBalanceWithStaked) return false; // at present agent will always require staked/bonded OLAS (or the ability to stake/bond) - return safeOlasBalanceWithStaked >= requiredOlas; + return safeOlasBalanceWithStaked >= requiredStakedOlas; } // case if agent is evicted and user has met the staking criteria if (isEligibleForStaking && isAgentEvicted) return true; - const hasEnoughOlas = (safeOlasBalanceWithStaked ?? 0) >= requiredOlas; - const hasEnoughEth = (totalEthBalance ?? 0) > requiredGas; + const hasEnoughOlas = + (safeOlasBalanceWithStaked ?? 0) >= requiredStakedOlas; + + const hasEnoughEth = (totalEthBalance ?? 0) > LOW_MASTER_SAFE_BALANCE; // TODO: refactor to be dynamic to services cross-chain return hasEnoughOlas && hasEnoughEth; }, [ isAllStakingContractDetailsRecordLoaded, deploymentStatus, isLowBalance, - requiredOlas, + requiredStakedOlas, hasEnoughServiceSlots, isServiceStaked, service, From 909b15754a677295f65656c4f6cf9fe34da617e2 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:08:22 +0000 Subject: [PATCH 259/463] feat: refactor AgentNotRunningButton to improve service polling management and streamline safe creation logic --- .../AgentButton/AgentNotRunningButton.tsx | 189 ++++++++---------- 1 file changed, 78 insertions(+), 111 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index 72bdc60e0..60361dd73 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -61,161 +61,128 @@ export const AgentNotRunningButton = (serviceConfigId: string) => { activeStakingProgramId, ); - // const minStakingDeposit = - // allStakingContractDetailsRecord?.[activeStakingProgram ?? defaultStakingProgram] - // ?.minStakingDeposit; - const requiredStakedOlas = service && STAKING_PROGRAMS[service.home_chain_id][activeStakingProgramId] - ?.stakingRequirements[TokenSymbol.OLAS]; // TODO: fix activeStakingProgramId + ?.stakingRequirements[TokenSymbol.OLAS]; - const safeOlasBalance = serviceSafeBalances.find((walletBalanceResult) => { - return walletBalanceResult.symbol === TokenSymbol.OLAS; - })?.balance; + const safeOlasBalance = serviceSafeBalances.find( + (walletBalanceResult) => walletBalanceResult.symbol === TokenSymbol.OLAS, + )?.balance; const safeOlasBalanceWithStaked = safeOlasBalance === undefined || totalStakedOlasBalance === undefined ? undefined : safeOlasBalance + totalStakedOlasBalance; - const handleStart = useCallback(async () => { - // Must have a wallet to start the agent - if (!wallets?.[0]) return; - - // Paused to stop overlapping service poll while wallet is created or service is built + const pauseAllPolling = useCallback(() => { setIsServicePollingPaused(true); - - // Paused to stop confusing balance transitions while starting the agent setIsBalancePollingPaused(true); - - // Paused to stop overlapping staking contract info poll while starting the agent setIsStakingContractInfoPollingPaused(true); + }, [ + setIsServicePollingPaused, + setIsBalancePollingPaused, + setIsStakingContractInfoPollingPaused, + ]); - // Mock "DEPLOYING" status (service polling will update this once resumed) - setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYING); + const resumeAllPolling = useCallback(() => { + setIsServicePollingPaused(false); + setIsBalancePollingPaused(false); + setIsStakingContractInfoPollingPaused(false); + }, [ + setIsServicePollingPaused, + setIsBalancePollingPaused, + setIsStakingContractInfoPollingPaused, + ]); - // Create master safe if it doesn't exist - try { - if ( - !service?.chain_configs[service.home_chain_id]?.chain_data?.multisig - ) { - await WalletService.createSafe(MiddlewareChain.OPTIMISM); - } - } catch (error) { - console.error(error); - // setServiceStatus(undefined); // TODO: reimplement state if it is missing - showNotification?.('Some error occurred while creating safe'); - setIsStakingContractInfoPollingPaused(false); - setIsServicePollingPaused(false); - setIsBalancePollingPaused(false); - return; + const createSafeIfNeeded = useCallback(async () => { + if (!service?.chain_configs[service.home_chain_id]?.chain_data?.multisig) { + await WalletService.createSafe(MiddlewareChain.OPTIMISM); } + }, [service]); + + const deployAndStartService = useCallback(async () => { + await ServicesService.createService({ + stakingProgramId: activeStakingProgramId, + serviceTemplate, + deploy: true, + useMechMarketplace: false, + }); + + await ServicesService.startService(serviceConfigId); + }, [activeStakingProgramId, serviceTemplate, serviceConfigId]); + + const updateStatesSequentially = useCallback(async () => { + await updateServicesState?.(); + await refetchActiveStakingContractDetails(); + await updateBalances(); + }, [ + updateServicesState, + refetchActiveStakingContractDetails, + updateBalances, + ]); - // Then create / deploy the service - try { - await ServicesService.createService({ - stakingProgramId: activeStakingProgramId, - serviceTemplate, - deploy: true, - useMechMarketplace: false, - }); - - await ServicesService.startService(serviceConfigId); - } catch (error) { - console.error(error); - // setServiceStatus(undefined); TODO: reimplement state if it is missing - showNotification?.('Some error occurred while deploying service'); - setIsServicePollingPaused(false); - setIsBalancePollingPaused(false); - setIsStakingContractInfoPollingPaused(false); - return; - } + const handleStart = useCallback(async () => { + if (!wallets?.[0]) return; + + pauseAllPolling(); + setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYING); - // Show success notification based on whether there was a service prior to starting try { + await createSafeIfNeeded(); + await deployAndStartService(); showNotification?.(`Your agent is running!`); - } catch (error) { - console.error(error); - showNotification?.( - 'Some error occurred while showing "running" notification', - ); - } - - // Can assume successful deployment - setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYED); + setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYED); - // TODO: remove this workaround, middleware should respond when agent is staked & confirmed running after `createService` call - await delayInSeconds(5); - - // update provider states sequentially - // service id is required before activeStakingContractDetails & balances can be updated - try { - await updateServicesState?.(); // reload the available services - await refetchActiveStakingContractDetails(); // reload active staking contract with new service - await updateBalances(); // reload the balances + await delayInSeconds(5); + await updateStatesSequentially(); } catch (error) { - console.error(error); + console.error('Error while starting the agent:', error); + showNotification?.('Some error occurred. Please try again.'); } finally { - // resume polling - setIsServicePollingPaused(false); - setIsStakingContractInfoPollingPaused(false); - setIsBalancePollingPaused(false); + resumeAllPolling(); } }, [ wallets, - setIsServicePollingPaused, - setIsBalancePollingPaused, - setIsStakingContractInfoPollingPaused, + pauseAllPolling, + resumeAllPolling, setDeploymentStatus, - service?.chain_configs, - service?.home_chain_id, + createSafeIfNeeded, + deployAndStartService, showNotification, - activeStakingProgramId, - serviceTemplate, - serviceConfigId, - updateServicesState, - refetchActiveStakingContractDetails, - updateBalances, + updateStatesSequentially, ]); const isDeployable = useMemo(() => { if (!isAllStakingContractDetailsRecordLoaded) return false; - // if the agent is NOT running and the balance is too low, - // user should not be able to start the agent const isServiceInactive = deploymentStatus === MiddlewareDeploymentStatus.BUILT || deploymentStatus === MiddlewareDeploymentStatus.STOPPED; - if (isServiceInactive && isLowBalance) { + if (isServiceInactive && isLowBalance) return false; + + if ( + [ + MiddlewareDeploymentStatus.DEPLOYED, + MiddlewareDeploymentStatus.DEPLOYING, + MiddlewareDeploymentStatus.STOPPING, + ].some((runningStatus) => deploymentStatus === runningStatus) + ) return false; - } - - if (deploymentStatus === MiddlewareDeploymentStatus.DEPLOYED) return false; - if (deploymentStatus === MiddlewareDeploymentStatus.DEPLOYING) return false; - if (deploymentStatus === MiddlewareDeploymentStatus.STOPPING) return false; - - if (!requiredStakedOlas) return false; - // If no slots available, agent cannot be started - if (!hasEnoughServiceSlots && !isServiceStaked) return false; + if (!requiredStakedOlas || (!hasEnoughServiceSlots && !isServiceStaked)) + return false; - // case where service exists & user has initial funded if (service && storeState?.isInitialFunded) { - if (!safeOlasBalanceWithStaked) return false; - // at present agent will always require staked/bonded OLAS (or the ability to stake/bond) - return safeOlasBalanceWithStaked >= requiredStakedOlas; + return (safeOlasBalanceWithStaked ?? 0) >= requiredStakedOlas; } - // case if agent is evicted and user has met the staking criteria if (isEligibleForStaking && isAgentEvicted) return true; - const hasEnoughOlas = - (safeOlasBalanceWithStaked ?? 0) >= requiredStakedOlas; - - const hasEnoughEth = (totalEthBalance ?? 0) > LOW_MASTER_SAFE_BALANCE; // TODO: refactor to be dynamic to services cross-chain - - return hasEnoughOlas && hasEnoughEth; + return ( + (safeOlasBalanceWithStaked ?? 0) >= requiredStakedOlas && + (totalEthBalance ?? 0) > LOW_MASTER_SAFE_BALANCE + ); }, [ isAllStakingContractDetailsRecordLoaded, deploymentStatus, From dfaba49f52f85facf33fd19327b67942c83f1647 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:14:21 +0000 Subject: [PATCH 260/463] fix: update LOW_MASTER_SAFE_BALANCE constant and add TODO for dynamic threshold implementation --- .../MainPage/header/AgentButton/AgentNotRunningButton.tsx | 2 +- frontend/constants/thresholds.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index 60361dd73..d67659d88 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -181,7 +181,7 @@ export const AgentNotRunningButton = (serviceConfigId: string) => { return ( (safeOlasBalanceWithStaked ?? 0) >= requiredStakedOlas && - (totalEthBalance ?? 0) > LOW_MASTER_SAFE_BALANCE + (totalEthBalance ?? 0) > LOW_MASTER_SAFE_BALANCE // TODO: change to service/chain dynamic threshold ); }, [ isAllStakingContractDetailsRecordLoaded, diff --git a/frontend/constants/thresholds.ts b/frontend/constants/thresholds.ts index 8a3546420..21cff2570 100644 --- a/frontend/constants/thresholds.ts +++ b/frontend/constants/thresholds.ts @@ -23,4 +23,5 @@ export const MIN_ETH_BALANCE_THRESHOLDS = { }; export const LOW_AGENT_SAFE_BALANCE = 0.5; + export const LOW_MASTER_SAFE_BALANCE = 2; From bfc988db3618fba44439fa1422d0fdf0c3c02324 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:23:05 +0000 Subject: [PATCH 261/463] fix: remove merge conflict markers and clean up walletAddress assignment in BalanceProvider --- frontend/context/BalanceProvider.tsx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index df6e9e835..2eb09d8e8 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -38,10 +38,7 @@ type CrossChainStakedBalances = Array<{ chainId: number; olasBondBalance: number; olasDepositBalance: number; -<<<<<<< HEAD walletAddress: Address; -======= ->>>>>>> refactor/balance-provider-hooks }>; export const BalanceContext = createContext<{ @@ -373,11 +370,8 @@ const getCrossChainStakedBalances = async ( olasDepositBalance: depositValue, serviceState, }), -<<<<<<< HEAD walletAddress: services[idx].chain_configs[chainId].chain_data.multisig!, // multisig must exist if registry info is fetched -======= ->>>>>>> refactor/balance-provider-hooks }); } else { console.error( From 23f5c6d545feef8976bf68de047efc5de4f6ca4b Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:38:33 +0000 Subject: [PATCH 262/463] feat: refactor GasBalanceSection to utilize service-specific balances and improve balance loading logic --- .../MainPage/sections/GasBalanceSection.tsx | 35 +++++++++++-------- frontend/hooks/useService.ts | 15 ++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index 8c5657d43..88d913962 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -1,16 +1,14 @@ -import { ArrowUpOutlined, InfoCircleOutlined } from '@ant-design/icons'; +import { InfoCircleOutlined } from '@ant-design/icons'; import { Skeleton, Tooltip, Typography } from 'antd'; import { isNil } from 'lodash'; import { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; -import { MiddlewareChain } from '@/client'; import { COLOR } from '@/constants/colors'; -import { EXPLORER_URL } from '@/constants/urls'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; +import { useService } from '@/hooks/useService'; import { useStore } from '@/hooks/useStore'; -import { useWallet } from '@/hooks/useWallet'; import { CardSection } from '../../styled/CardSection'; @@ -36,16 +34,18 @@ const FineDot = styled(Dot)` `; const BalanceStatus = () => { - const { isBalanceLoaded, isLowBalance } = useBalanceContext(); + const { isLoaded, lowBalances } = useBalanceContext(); const { storeState } = useStore(); const { showNotification } = useElectronApi(); const [isLowBalanceNotificationShown, setIsLowBalanceNotificationShown] = useState(false); + const isLowBalance = lowBalances.length > 0; + // show notification if balance is too low useEffect(() => { - if (!isBalanceLoaded) return; + if (!isLoaded) return; if (!showNotification) return; if (!storeState?.isInitialFunded) return; @@ -60,7 +60,7 @@ const BalanceStatus = () => { setIsLowBalanceNotificationShown(false); } }, [ - isBalanceLoaded, + isLoaded, isLowBalanceNotificationShown, isLowBalance, showNotification, @@ -96,9 +96,13 @@ const TooltipContent = styled.div` } `; -export const GasBalanceSection = () => { - const { masterSafeAddress } = useWallet(); - const { isBalanceLoaded } = useBalanceContext(); +export const GasBalanceSection = ({ + serviceConfigId, +}: { + serviceConfigId: string; +}) => { + const { isLoaded } = useBalanceContext(); + const { masterSafes } = useService({ serviceConfigId }); return ( { > Trading balance  - {masterSafeAddress && ( + {masterSafes.length > 0 && ( Your agent uses this balance to fund trading activity on-chain. -
+ {/* TODO: reintroduce, low prio */} + {/*
Track activity on blockchain explorer{' '} - + */} } > @@ -133,7 +138,7 @@ export const GasBalanceSection = () => { )}
- {isBalanceLoaded ? ( + {isLoaded ? ( diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index ee09879a3..27b4c256c 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -3,9 +3,11 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { WalletOwnerType, WalletType } from '@/enums/Wallet'; import { Address } from '@/types/Address'; import { useServices } from './useServices'; +import { useWallet } from './useWallet'; type ServiceChainIdAddressRecord = { [chainId: number]: { @@ -24,6 +26,7 @@ export const useService = ({ }) => { const { services, isFetched: isLoaded } = useServices(); const queryClient = useQueryClient(); + const { wallets } = useWallet(); const service = useMemo(() => { return services?.find( @@ -66,6 +69,17 @@ export const useService = ({ }, [] as Address[]); }, [addresses]); + const masterSafes = useMemo(() => { + return ( + wallets?.filter( + (wallet) => + flatAddresses.includes(wallet.address) && + wallet.owner === WalletOwnerType.Master && + wallet.type === WalletType.Safe, + ) ?? [] + ); + }, [flatAddresses, wallets]); + /** * Overrides the deployment status of the service in the cache. * @note Overwrite is only temporary if ServicesContext is polling @@ -87,6 +101,7 @@ export const useService = ({ isLoaded, deploymentStatus, setDeploymentStatus, + masterSafes, }; }; From dfa62b37d17a6d1ca59a5ea1179d3d578a65397c Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:43:57 +0000 Subject: [PATCH 263/463] feat: update BalanceStatus component to accept serviceConfigId prop for low balance specific to selected service --- .../components/MainPage/sections/GasBalanceSection.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index 88d913962..810c132e8 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -33,7 +33,7 @@ const FineDot = styled(Dot)` background-color: ${COLOR.GREEN_2}; `; -const BalanceStatus = () => { +const BalanceStatus = ({ serviceConfigId }: { serviceConfigId: string }) => { const { isLoaded, lowBalances } = useBalanceContext(); const { storeState } = useStore(); const { showNotification } = useElectronApi(); @@ -41,7 +41,11 @@ const BalanceStatus = () => { const [isLowBalanceNotificationShown, setIsLowBalanceNotificationShown] = useState(false); - const isLowBalance = lowBalances.length > 0; + const isLowBalance = + lowBalances.filter( + (lowBalanceResult) => + lowBalanceResult.serviceConfigId === serviceConfigId, + ).length > 0; // show notification if balance is too low useEffect(() => { @@ -140,7 +144,7 @@ export const GasBalanceSection = ({ {isLoaded ? ( - + ) : ( From 988696187ef7b60ef2a0623bafb74e9f014c5a92 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:50:59 +0000 Subject: [PATCH 264/463] fix: update BalanceStatus prop to use serviceConfigId for consistency --- frontend/components/MainPage/sections/GasBalanceSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index 810c132e8..9b4249135 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -144,7 +144,7 @@ export const GasBalanceSection = ({ {isLoaded ? ( - + ) : ( From cbe5a0da835f89d6897062b1aa3b166ef09145d9 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 12:53:22 +0000 Subject: [PATCH 265/463] fix: rename balance loading state variable for clarity in OlasBalanceSection --- frontend/components/MainPage/sections/OlasBalanceSection.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/MainPage/sections/OlasBalanceSection.tsx b/frontend/components/MainPage/sections/OlasBalanceSection.tsx index 1e39b597b..1132bd5a0 100644 --- a/frontend/components/MainPage/sections/OlasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/OlasBalanceSection.tsx @@ -22,7 +22,7 @@ type MainOlasBalanceProps = { isBorderTopVisible?: boolean }; export const MainOlasBalance = ({ isBorderTopVisible = true, }: MainOlasBalanceProps) => { - const { isBalanceLoaded, totalOlasBalance } = useBalanceContext(); + const { isLoaded: isBalanceLoaded, totalOlasBalance } = useBalanceContext(); // const { goto } = usePageState(); const balance = useMemo(() => { From 4b1f03bac9a4438bf94bcfe6ea113ce791cef8b4 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:17:00 +0000 Subject: [PATCH 266/463] fix: services types --- frontend/context/ServicesProvider.tsx | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 23f7e758a..ec3a673a1 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -16,7 +16,13 @@ import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; -import { AgentWallets, WalletOwnerType, WalletType } from '@/enums/Wallet'; +import { + AgentEoa, + AgentSafe, + AgentWallets, + WalletOwnerType, + WalletType, +} from '@/enums/Wallet'; import { UsePause, usePause } from '@/hooks/usePause'; import { ServicesService } from '@/service/Services'; import { AgentConfig } from '@/types/Agent'; @@ -137,11 +143,14 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { if (instances) { acc.push( - ...instances.map((instance: string) => ({ - address: instance, - type: WalletType.EOA, - owner: WalletOwnerType.Agent, - })), + ...instances.map( + (instance: string) => + ({ + address: instance, + type: WalletType.EOA, + owner: WalletOwnerType.Agent, + }) as AgentEoa, + ), ); } @@ -151,7 +160,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { type: WalletType.Safe, owner: WalletOwnerType.Agent, chainId, - }); + } as AgentSafe); } return acc; From 06ca2d5942b9cc570bdc770a8af0bf6c4b371738 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:17:17 +0000 Subject: [PATCH 267/463] chore: not convinced this provider is needed --- frontend/context/MasterSafeProvider.tsx | 90 ------------------- .../context/backup/MasterSafeProvider.tsx | 90 +++++++++++++++++++ 2 files changed, 90 insertions(+), 90 deletions(-) delete mode 100644 frontend/context/MasterSafeProvider.tsx create mode 100644 frontend/context/backup/MasterSafeProvider.tsx diff --git a/frontend/context/MasterSafeProvider.tsx b/frontend/context/MasterSafeProvider.tsx deleted file mode 100644 index 0ff84e89d..000000000 --- a/frontend/context/MasterSafeProvider.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { - createContext, - PropsWithChildren, - useContext, - useMemo, - useState, -} from 'react'; -import { useInterval } from 'usehooks-ts'; - -import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; -import { GnosisSafeService } from '@/service/GnosisSafe'; -import { Address } from '@/types/Address'; - -import { OnlineStatusContext } from './OnlineStatusProvider'; -import { WalletContext } from './WalletProvider'; - -export const MasterSafeContext = createContext<{ - backupSafeAddress?: Address; - masterSafeAddress?: Address; - masterEoaAddress?: Address; - masterSafeOwners?: Address[]; - updateMasterSafeOwners: () => Promise; -}>({ - backupSafeAddress: undefined, - masterSafeAddress: undefined, - masterEoaAddress: undefined, - masterSafeOwners: undefined, - updateMasterSafeOwners: async () => {}, -}); - -export const MasterSafeProvider = ({ children }: PropsWithChildren) => { - const { isOnline } = useContext(OnlineStatusContext); - const { masterSafeAddress, masterEoaAddress } = useContext(WalletContext); - - const [masterSafeOwners, setMasterSafeOwners] = useState(); - - const backupSafeAddress = useMemo
(() => { - if (!masterEoaAddress) return; - if (!masterSafeOwners) return; - if (!masterSafeOwners.length) return; - if ( - !masterSafeOwners.find( - (address) => address.toLowerCase() === masterEoaAddress.toLowerCase(), - ) - ) { - console.error('Safe not owned by master EOA'); - return; - } - - const currentBackupAddress = masterSafeOwners.find( - (address) => address !== masterEoaAddress, - ); - - return currentBackupAddress; - }, [masterEoaAddress, masterSafeOwners]); - - const updateMasterSafeOwners = async () => { - if (!masterSafeAddress) return; - try { - const safeSigners = await GnosisSafeService.getOwners({ - address: masterSafeAddress, - }); - if (!safeSigners) return; - setMasterSafeOwners(safeSigners); - } catch (error) { - console.error('Error fetching safe owners', error); - } - }; - - useInterval( - updateMasterSafeOwners, - (masterSafeOwners && masterSafeOwners.length >= 2) || !isOnline - ? null - : FIVE_SECONDS_INTERVAL, - ); - - return ( - - {children} - - ); -}; diff --git a/frontend/context/backup/MasterSafeProvider.tsx b/frontend/context/backup/MasterSafeProvider.tsx new file mode 100644 index 000000000..33e067adc --- /dev/null +++ b/frontend/context/backup/MasterSafeProvider.tsx @@ -0,0 +1,90 @@ +// import { +// createContext, +// PropsWithChildren, +// useContext, +// useMemo, +// useState, +// } from 'react'; +// import { useInterval } from 'usehooks-ts'; + +// import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +// import { GnosisSafeService } from '@/service/GnosisSafe'; +// import { Address } from '@/types/Address'; + +// import { OnlineStatusContext } from './OnlineStatusProvider'; +// import { WalletContext } from './WalletProvider'; + +// export const MasterSafeContext = createContext<{ +// backupSafeAddress?: Address; +// masterSafeAddress?: Address; +// masterEoaAddress?: Address; +// masterSafeOwners?: Address[]; +// updateMasterSafeOwners: () => Promise; +// }>({ +// backupSafeAddress: undefined, +// masterSafeAddress: undefined, +// masterEoaAddress: undefined, +// masterSafeOwners: undefined, +// updateMasterSafeOwners: async () => {}, +// }); + +// export const MasterSafeProvider = ({ children }: PropsWithChildren) => { +// const { isOnline } = useContext(OnlineStatusContext); +// const { masterSafeAddress, masterEoaAddress } = useContext(WalletContext); + +// const [masterSafeOwners, setMasterSafeOwners] = useState(); + +// const backupSafeAddress = useMemo
(() => { +// if (!masterEoaAddress) return; +// if (!masterSafeOwners) return; +// if (!masterSafeOwners.length) return; +// if ( +// !masterSafeOwners.find( +// (address) => address.toLowerCase() === masterEoaAddress.toLowerCase(), +// ) +// ) { +// console.error('Safe not owned by master EOA'); +// return; +// } + +// const currentBackupAddress = masterSafeOwners.find( +// (address) => address !== masterEoaAddress, +// ); + +// return currentBackupAddress; +// }, [masterEoaAddress, masterSafeOwners]); + +// const updateMasterSafeOwners = async () => { +// if (!masterSafeAddress) return; +// try { +// const safeSigners = await GnosisSafeService.getOwners({ +// address: masterSafeAddress, +// }); +// if (!safeSigners) return; +// setMasterSafeOwners(safeSigners); +// } catch (error) { +// console.error('Error fetching safe owners', error); +// } +// }; + +// useInterval( +// updateMasterSafeOwners, +// (masterSafeOwners && masterSafeOwners.length >= 2) || !isOnline +// ? null +// : FIVE_SECONDS_INTERVAL, +// ); + +// return ( +// +// {children} +// +// ); +// }; From ea9c2e33817a937bbf740b58026021cbd20a9367 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:17:42 +0000 Subject: [PATCH 268/463] refactor: remove unused MasterSafeProvider from App component --- frontend/pages/_app.tsx | 53 +++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 6fd28a202..27160208e 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -8,7 +8,6 @@ import { useEffect, useState } from 'react'; import { Layout } from '@/components/Layout'; import { BalanceProvider } from '@/context/BalanceProvider'; import { ElectronApiProvider } from '@/context/ElectronApiProvider'; -import { MasterSafeProvider } from '@/context/MasterSafeProvider'; import { ModalProvider } from '@/context/ModalProvider'; import { OnlineStatusProvider } from '@/context/OnlineStatusProvider'; import { PageStateProvider } from '@/context/PageStateProvider'; @@ -42,33 +41,31 @@ export default function App({ Component, pageProps }: AppProps) { - - - - - - - - - - {isMounted ? ( - - - - - - - - ) : null} - - - - - - - - - + + + + + + + + + {isMounted ? ( + + + + + + + + ) : null} + + + + + + + + From 708688dba2b66d9b4c11dcd9e85d0870e3622ad1 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:17:49 +0000 Subject: [PATCH 269/463] refactor: update SystemNotificationTriggers to use selectedService instead of serviceStatus --- frontend/context/SystemNotificationTriggers.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/frontend/context/SystemNotificationTriggers.tsx b/frontend/context/SystemNotificationTriggers.tsx index 70fc06318..94e8b42a6 100644 --- a/frontend/context/SystemNotificationTriggers.tsx +++ b/frontend/context/SystemNotificationTriggers.tsx @@ -12,7 +12,7 @@ const Notifications = { export const SystemNotificationTriggers = ({ children }: PropsWithChildren) => { const electronApi = useElectronApi(); - const { serviceStatus } = useServices(); + const { selectedService } = useServices(); const { isEligibleForRewards } = useReward(); const prevIsEligibleForRewards = useRef(); @@ -22,7 +22,10 @@ export const SystemNotificationTriggers = ({ children }: PropsWithChildren) => { if (!electronApi.showNotification) return; // ignore if agent is not running - if (serviceStatus !== MiddlewareDeploymentStatus.DEPLOYED) return; + if ( + selectedService?.deploymentStatus !== MiddlewareDeploymentStatus.DEPLOYED + ) + return; // ignore if eligibility is not yet defined if (isEligibleForRewards === undefined) return; // ignore if agent was previously eligible and is still eligible @@ -37,13 +40,13 @@ export const SystemNotificationTriggers = ({ children }: PropsWithChildren) => { } prevIsEligibleForRewards.current = isEligibleForRewards; - }, [electronApi, isEligibleForRewards, serviceStatus]); + }, [electronApi, isEligibleForRewards, selectedService?.deploymentStatus]); useEffect(() => { if (!electronApi.showNotification) return; // Show notification when agent earns rewards handleAgentEarned(); - }, [electronApi, handleAgentEarned, isEligibleForRewards, serviceStatus]); + }, [electronApi, handleAgentEarned, isEligibleForRewards]); return children; }; From 34e989b2613bcf346153ab8555a6976ee91c2d2c Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:32:26 +0000 Subject: [PATCH 270/463] refactor: wallet types, organize, add more --- frontend/enums/Wallet.ts | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts index f0498180e..66a9b9102 100644 --- a/frontend/enums/Wallet.ts +++ b/frontend/enums/Wallet.ts @@ -11,35 +11,38 @@ export enum WalletOwnerType { Agent = 'agent', } -export type MasterEoa = { +export type Eoa = { address: Address; type: WalletType.EOA; - owner: WalletOwnerType.Master; }; -export type MasterSafe = Omit & { +export type Safe = { + address: Address; type: WalletType.Safe; chainId: ChainId; }; -export type MasterWallet = MasterEoa | MasterSafe; +export type MasterEoa = Eoa & { + owner: WalletOwnerType.Master; +}; -export type AgentEoa = { - address: Address; - type: WalletType.EOA; +export type AgentEoa = Eoa & { owner: WalletOwnerType.Agent; }; -export type AgentSafe = Omit & { - type: WalletType.Safe; - chainId: ChainId; +export type MasterSafe = Safe & { + owner: WalletOwnerType.Master; }; -export type AgentWallet = AgentEoa | AgentSafe; +export type AgentSafe = Safe & { + owner: WalletOwnerType.Agent; +}; -export type Wallet = MasterWallet | AgentWallet; +export type MasterWallet = MasterEoa | MasterSafe; +export type AgentWallet = AgentEoa | AgentSafe; export type MasterWallets = MasterWallet[]; export type AgentWallets = AgentWallet[]; +export type Wallet = MasterWallet | AgentWallet; export type Wallets = Wallet[]; From d164d9b54cc16a79a2bbff3d98ff584a72c3b686 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:33:10 +0000 Subject: [PATCH 271/463] refactor: remove unused MasterSafeProvider component --- .../context/backup/MasterSafeProvider.tsx | 90 ------------------- 1 file changed, 90 deletions(-) delete mode 100644 frontend/context/backup/MasterSafeProvider.tsx diff --git a/frontend/context/backup/MasterSafeProvider.tsx b/frontend/context/backup/MasterSafeProvider.tsx deleted file mode 100644 index 33e067adc..000000000 --- a/frontend/context/backup/MasterSafeProvider.tsx +++ /dev/null @@ -1,90 +0,0 @@ -// import { -// createContext, -// PropsWithChildren, -// useContext, -// useMemo, -// useState, -// } from 'react'; -// import { useInterval } from 'usehooks-ts'; - -// import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; -// import { GnosisSafeService } from '@/service/GnosisSafe'; -// import { Address } from '@/types/Address'; - -// import { OnlineStatusContext } from './OnlineStatusProvider'; -// import { WalletContext } from './WalletProvider'; - -// export const MasterSafeContext = createContext<{ -// backupSafeAddress?: Address; -// masterSafeAddress?: Address; -// masterEoaAddress?: Address; -// masterSafeOwners?: Address[]; -// updateMasterSafeOwners: () => Promise; -// }>({ -// backupSafeAddress: undefined, -// masterSafeAddress: undefined, -// masterEoaAddress: undefined, -// masterSafeOwners: undefined, -// updateMasterSafeOwners: async () => {}, -// }); - -// export const MasterSafeProvider = ({ children }: PropsWithChildren) => { -// const { isOnline } = useContext(OnlineStatusContext); -// const { masterSafeAddress, masterEoaAddress } = useContext(WalletContext); - -// const [masterSafeOwners, setMasterSafeOwners] = useState(); - -// const backupSafeAddress = useMemo
(() => { -// if (!masterEoaAddress) return; -// if (!masterSafeOwners) return; -// if (!masterSafeOwners.length) return; -// if ( -// !masterSafeOwners.find( -// (address) => address.toLowerCase() === masterEoaAddress.toLowerCase(), -// ) -// ) { -// console.error('Safe not owned by master EOA'); -// return; -// } - -// const currentBackupAddress = masterSafeOwners.find( -// (address) => address !== masterEoaAddress, -// ); - -// return currentBackupAddress; -// }, [masterEoaAddress, masterSafeOwners]); - -// const updateMasterSafeOwners = async () => { -// if (!masterSafeAddress) return; -// try { -// const safeSigners = await GnosisSafeService.getOwners({ -// address: masterSafeAddress, -// }); -// if (!safeSigners) return; -// setMasterSafeOwners(safeSigners); -// } catch (error) { -// console.error('Error fetching safe owners', error); -// } -// }; - -// useInterval( -// updateMasterSafeOwners, -// (masterSafeOwners && masterSafeOwners.length >= 2) || !isOnline -// ? null -// : FIVE_SECONDS_INTERVAL, -// ); - -// return ( -// -// {children} -// -// ); -// }; From 2002704318be071f608153433e04201e27db1930 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:33:18 +0000 Subject: [PATCH 272/463] refactor: add multisig query key for retrieving owners --- frontend/constants/react-query-keys.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index 4592ad2aa..aacf5250a 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -1,3 +1,5 @@ +import { Safe } from '@/enums/Wallet'; + export const REACT_QUERY_KEYS = { // services SERVICES_KEY: ['services'] as const, @@ -59,4 +61,8 @@ export const REACT_QUERY_KEYS = { ] as const, REWARDS_HISTORY_KEY: (chainId: number, serviceId: number) => ['rewardsHistory', chainId, serviceId] as const, + + // multisigs + MULTISIG_GET_OWNERS_KEY: (multisig: Safe) => + ['multisig', 'getOwners', multisig.chainId, multisig.address] as const, } as const; From 41f157accf0e1e378f067d0ac66c22e4ace4ea27 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:34:36 +0000 Subject: [PATCH 273/463] refactor: remove GnosisSafe service file --- frontend/service/GnosisSafe.ts | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 frontend/service/GnosisSafe.ts diff --git a/frontend/service/GnosisSafe.ts b/frontend/service/GnosisSafe.ts deleted file mode 100644 index f4155ee43..000000000 --- a/frontend/service/GnosisSafe.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Contract } from 'ethers-multicall'; - -import { GNOSIS_SAFE_ABI } from '@/abis/gnosisSafe'; -import { ChainId } from '@/enums/Chain'; -import { Address } from '@/types/Address'; - -const getOwners = async ({ - address, -}: { - address: Address; - chainId: ChainId; -}): Promise => { - const gnosisSafeContract = new Contract(address, GNOSIS_SAFE_ABI); - - return gnosisSafeContract.getOwners(); -}; - -export const GnosisSafeService = { - getOwners, -}; From 82f8963d815ec778359a398d1bf275959eeeb5da Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:34:40 +0000 Subject: [PATCH 274/463] refactor: update useMasterSafe hook to use react-query for fetching owners --- frontend/hooks/useMasterSafe.ts | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/frontend/hooks/useMasterSafe.ts b/frontend/hooks/useMasterSafe.ts index ec5d52059..e4f2cde5d 100644 --- a/frontend/hooks/useMasterSafe.ts +++ b/frontend/hooks/useMasterSafe.ts @@ -1,7 +1,22 @@ -import { useContext } from 'react'; +import { useQuery } from '@tanstack/react-query'; +import { Contract } from 'ethers'; -import { MasterSafeContext } from '@/context/MasterSafeProvider'; +import { GNOSIS_SAFE_ABI } from '@/abis/gnosisSafe'; +import { PROVIDERS } from '@/constants/providers'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { MasterSafe } from '@/enums/Wallet'; +import { Address } from '@/types/Address'; -export const useMasterSafe = () => { - return useContext(MasterSafeContext); +export const useMasterSafe = (masterSafe: MasterSafe) => { + return useQuery({ + queryKey: REACT_QUERY_KEYS.MULTISIG_GET_OWNERS_KEY(masterSafe), + queryFn: async () => { + const contract = new Contract( + masterSafe.address, + GNOSIS_SAFE_ABI, + PROVIDERS[masterSafe.chainId].provider, + ); + return contract.functions.getOwners() as Promise; + }, + }); }; From f986a5a711f4d12d10594279016018409e83c206 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:36:37 +0000 Subject: [PATCH 275/463] refactor: replace useMasterSafe with useMultisig for more generic approach --- .../hooks/{useMasterSafe.ts => useMultisig.ts} | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) rename frontend/hooks/{useMasterSafe.ts => useMultisig.ts} (59%) diff --git a/frontend/hooks/useMasterSafe.ts b/frontend/hooks/useMultisig.ts similarity index 59% rename from frontend/hooks/useMasterSafe.ts rename to frontend/hooks/useMultisig.ts index e4f2cde5d..824ce4a2d 100644 --- a/frontend/hooks/useMasterSafe.ts +++ b/frontend/hooks/useMultisig.ts @@ -4,17 +4,23 @@ import { Contract } from 'ethers'; import { GNOSIS_SAFE_ABI } from '@/abis/gnosisSafe'; import { PROVIDERS } from '@/constants/providers'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; -import { MasterSafe } from '@/enums/Wallet'; +import { Safe } from '@/enums/Wallet'; import { Address } from '@/types/Address'; -export const useMasterSafe = (masterSafe: MasterSafe) => { +/** + * Hook to fetch multisig owners + * @param safe + * @returns multisig owners + * @note extend with further multisig functions as needed + */ +export const useMultisig = (safe: Safe) => { return useQuery({ - queryKey: REACT_QUERY_KEYS.MULTISIG_GET_OWNERS_KEY(masterSafe), + queryKey: REACT_QUERY_KEYS.MULTISIG_GET_OWNERS_KEY(safe), queryFn: async () => { const contract = new Contract( - masterSafe.address, + safe.address, GNOSIS_SAFE_ABI, - PROVIDERS[masterSafe.chainId].provider, + PROVIDERS[safe.chainId].provider, ); return contract.functions.getOwners() as Promise; }, From 42c4204f6b60c61d2ce36be6296df84222f6e784 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:38:46 +0000 Subject: [PATCH 276/463] fix: replace add backup wallet alert --- .../sections/AlertSections/AddBackupWalletAlert.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx index 8d9d44a90..675622361 100644 --- a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx +++ b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx @@ -2,19 +2,20 @@ import { Flex, Typography } from 'antd'; import { isNil } from 'lodash'; import { Pages } from '@/enums/Pages'; -import { useMasterSafe } from '@/hooks/useMasterSafe'; +import { MasterSafe } from '@/enums/Wallet'; +import { useMultisig } from '@/hooks/useMultisig'; import { usePageState } from '@/hooks/usePageState'; import { CustomAlert } from '../../../Alert'; const { Text } = Typography; -export const AddBackupWalletAlert = () => { +export const AddBackupWalletAlert = (masterSafe: MasterSafe) => { const { goto } = usePageState(); - const { backupSafeAddress, masterSafeOwners } = useMasterSafe(); + const { data: masterSafeOwners } = useMultisig(masterSafe); if (isNil(masterSafeOwners)) return null; - if (backupSafeAddress) return null; + if (masterSafeOwners) return null; return ( Date: Wed, 20 Nov 2024 16:45:12 +0000 Subject: [PATCH 277/463] refactor: migrate from useMasterSafe to useMultisig for improved functionality --- .../sections/AlertSections/AddBackupWalletAlert.tsx | 11 +++++++---- frontend/hooks/useMultisig.ts | 10 +++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx index 675622361..2428d3f12 100644 --- a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx +++ b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx @@ -1,5 +1,5 @@ import { Flex, Typography } from 'antd'; -import { isNil } from 'lodash'; +import { isArray } from 'lodash'; import { Pages } from '@/enums/Pages'; import { MasterSafe } from '@/enums/Wallet'; @@ -12,10 +12,13 @@ const { Text } = Typography; export const AddBackupWalletAlert = (masterSafe: MasterSafe) => { const { goto } = usePageState(); - const { data: masterSafeOwners } = useMultisig(masterSafe); + const { owners, ownersIsPending, ownersIsFetched } = useMultisig(masterSafe); - if (isNil(masterSafeOwners)) return null; - if (masterSafeOwners) return null; + if (ownersIsPending) return null; + if (!ownersIsFetched) return null; + + // all safes have min 1 owner, more than 1 owner, there is a backup + if (isArray(owners) && owners.length > 1) return null; return ( { - return useQuery({ + const { + data: owners, + isFetched: ownersIsFetched, + isPending: ownersIsPending, + } = useQuery({ queryKey: REACT_QUERY_KEYS.MULTISIG_GET_OWNERS_KEY(safe), queryFn: async () => { const contract = new Contract( @@ -24,5 +29,8 @@ export const useMultisig = (safe: Safe) => { ); return contract.functions.getOwners() as Promise; }, + refetchInterval: FIVE_SECONDS_INTERVAL, }); + + return { owners, ownersIsFetched, ownersIsPending }; }; From 64d4abb7d88b507faf73e82002ffd165f9aedbdc Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:47:19 +0000 Subject: [PATCH 278/463] refactor: rename WalletProvider to MasterWalletProvider for clarity --- frontend/pages/_app.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 27160208e..709e5f2ca 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -19,7 +19,7 @@ import { StakingContractDetailsProvider } from '@/context/StakingContractDetails import { StakingProgramProvider } from '@/context/StakingProgramProvider'; import { StoreProvider } from '@/context/StoreProvider'; import { SystemNotificationTriggers } from '@/context/SystemNotificationTriggers'; -import { WalletProvider } from '@/context/WalletProvider'; +import { MasterWalletProvider } from '@/context/WalletProvider'; import { mainTheme } from '@/theme'; import { setupMulticallAddresses } from '@/utils/setupMulticall'; @@ -40,7 +40,7 @@ export default function App({ Component, pageProps }: AppProps) { - + @@ -66,7 +66,7 @@ export default function App({ Component, pageProps }: AppProps) { - + From de7834c5e7434c26221dea38845c8e752db9e62c Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:47:33 +0000 Subject: [PATCH 279/463] refactor: update AgentNotRunningButton to use useMasterWalletContext for wallet management --- .../MainPage/header/AgentButton/AgentNotRunningButton.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index d67659d88..08dc49255 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -20,14 +20,14 @@ import { } from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { useStore } from '@/hooks/useStore'; -import { useWallet } from '@/hooks/useWallet'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { ServicesService } from '@/service/Services'; import { WalletService } from '@/service/Wallet'; import { delayInSeconds } from '@/utils/delay'; /** Button used to start / deploy the agent */ export const AgentNotRunningButton = (serviceConfigId: string) => { - const { wallets } = useWallet(); + const { wallets } = useMasterWalletContext(); const { selectedService, setPaused: setIsServicePollingPaused, From 8601847f653f84c4aec6a82f5164174e0d0912ca Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:47:48 +0000 Subject: [PATCH 280/463] refactor: update AddFundsSection to use useMasterWalletContext for wallet management --- frontend/components/MainPage/sections/AddFundsSection.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index 444546228..b7ab3dd87 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -22,7 +22,7 @@ import { CHAIN_CONFIG } from '@/config/chains'; import { TOKEN_CONFIG } from '@/config/tokens'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { COW_SWAP_GNOSIS_XDAI_OLAS_URL } from '@/constants/urls'; -import { useWallet } from '@/hooks/useWallet'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { copyToClipboard } from '@/utils/copyToClipboard'; import { delayInSeconds } from '@/utils/delay'; import { truncateAddress } from '@/utils/truncate'; @@ -77,7 +77,7 @@ export const AddFundsSection = () => { }; export const OpenAddFundsSection = forwardRef((_, ref) => { - const { masterSafeAddress } = useWallet(); + const { masterSafeAddress } = useMasterWalletContext(); const truncatedFundingAddress: string | undefined = useMemo( () => masterSafeAddress && truncateAddress(masterSafeAddress, 4), From 0692f001a84353aafa2061275bd0f0e026177426 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 16:56:57 +0000 Subject: [PATCH 281/463] refactor: update AddBackupWalletViaSafePage to use masterSafe for improved wallet management --- .../AddBackupWalletViaSafePage/index.tsx | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx index fa7235dab..bc26862f6 100644 --- a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx +++ b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx @@ -3,14 +3,27 @@ import { Card, Flex, Typography } from 'antd'; import { CardTitle } from '@/components/Card/CardTitle'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { DISCORD_TICKET_URL } from '@/constants/urls'; -import { useWallet } from '@/hooks/useWallet'; +import { ChainId } from '@/enums/Chain'; +import { MasterSafe } from '@/enums/Wallet'; import { GoToMainPageButton } from '../GoToMainPageButton'; const { Text } = Typography; -export const AddBackupWalletViaSafePage = () => { - const { masterSafeAddress } = useWallet(); +/** + * update as needed; check https://app.safe.global/new-safe/create for prefixes + */ +const safeChainPrefix = { + [ChainId.Ethereum]: 'eth', + [ChainId.Base]: 'base', + [ChainId.Optimism]: 'oeth', + [ChainId.Gnosis]: 'gno', +}; + +export const AddBackupWalletViaSafePage = (masterSafe: MasterSafe) => { + const { chainId, address } = masterSafe; + + const safePrefix = safeChainPrefix[chainId]; return ( { Manually add backup wallet via Safe interface: Add backup wallet {UNICODE_SYMBOLS.EXTERNAL_LINK} From 2ad650aa439074f85494bed8ea6ff78c7e3e8370 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 17:46:59 +0000 Subject: [PATCH 282/463] refactor: debug section --- .../SettingsPage/DebugInfoSection.tsx | 117 ++++++++++++------ 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/frontend/components/SettingsPage/DebugInfoSection.tsx b/frontend/components/SettingsPage/DebugInfoSection.tsx index 31b0cc7d4..3768a94a3 100644 --- a/frontend/components/SettingsPage/DebugInfoSection.tsx +++ b/frontend/components/SettingsPage/DebugInfoSection.tsx @@ -17,13 +17,15 @@ import { COLOR } from '@/constants/colors'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { EXPLORER_URL } from '@/constants/urls'; import { MODAL_WIDTH } from '@/constants/width'; +import { WalletBalanceResult } from '@/context/BalanceProvider'; +import { ChainId, ChainName } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; +import { WalletType } from '@/enums/Wallet'; import { useAddress } from '@/hooks/useAddress'; import { useBalanceContext } from '@/hooks/useBalanceContext'; -import { useWallet } from '@/hooks/useWallet'; -import { WalletAddressNumberRecord } from '@/types/Records'; +import { useMasterWalletContext } from '@/hooks/useWallet'; +import { Address } from '@/types/Address'; import { copyToClipboard } from '@/utils/copyToClipboard'; -import { balanceFormat } from '@/utils/numberFormatters'; import { truncateAddress } from '@/utils/truncate'; import { CardSection } from '../styled/CardSection'; @@ -38,29 +40,31 @@ const Card = styled.div` const ICON_STYLE = { color: '#606F85' }; -const getItemData = ( - walletBalances: WalletAddressNumberRecord, - address: `0x${string}`, -) => ({ - balance: { - OLAS: balanceFormat(walletBalances[address]?.OLAS, 2), - ETH: balanceFormat(walletBalances[address]?.ETH, 2), - }, - address: address, - truncatedAddress: address ? truncateAddress(address) : '', -}); +const getBalanceData = (walletBalances: WalletBalanceResult[]) => { + const result: { [chainId: number]: { [tokenSymbol: string]: number } } = {}; + + for (const walletBalanceResult of walletBalances) { + const { chainId, symbol } = walletBalanceResult; + if (!result[chainId]) result[chainId] = {}; + if (!result[chainId][symbol]) result[chainId][symbol] = 0; + result[chainId][symbol] += walletBalanceResult.balance; + } + + return { balance: result }; +}; const DebugItem = ({ item, }: { item: { title: string; - balance: Record; + balance: Record>; address: `0x${string}`; - truncatedAddress: string; link?: { title: string; href: string }; }; }) => { + const truncatedAddress = truncateAddress(item.address); + const onCopyToClipboard = useCallback( () => copyToClipboard(item.address).then(() => @@ -80,9 +84,23 @@ const DebugItem = ({ Balance - {item.balance.OLAS} OLAS - {item.balance.ETH} ETH - {/* {item.balance.USDC} USDC */} + {Object.entries(item.balance).map(([chainId, balance]) => { + return ( + + + {ChainName[+chainId as keyof typeof ChainName]} + + {Object.entries(balance).map(([tokenSymbol, balance]) => { + return ( + + {balance} + {tokenSymbol} + + ); + })} + + ); + })} @@ -92,12 +110,12 @@ const DebugItem = ({ Address - - {item.truncatedAddress} - + > */} + {truncatedAddress} + {/* */} @@ -117,7 +135,7 @@ const DebugItem = ({ }; export const DebugInfoSection = () => { - const { wallets, masterEoaAddress, masterSafeAddress } = useWallet(); + const { wallets } = useMasterWalletContext(); const { instanceAddress, multisigAddress } = useAddress(); const { walletBalances } = useBalanceContext(); @@ -125,44 +143,73 @@ export const DebugInfoSection = () => { const showModal = useCallback(() => setIsModalOpen(true), []); const handleCancel = useCallback(() => setIsModalOpen(false), []); + const masterEoas = wallets?.filter( + (wallet) => wallet.type === WalletType.EOA, + ); + + const masterSafes = wallets?.filter( + (wallet) => wallet.type === WalletType.Safe, + ); + const data = useMemo(() => { if (!wallets?.length) return null; - const result = []; + const result: { + title: string; + balance: Record>; + address: Address; + link?: { title: string; href: string }; + }[] = []; - if (masterEoaAddress) { + masterEoas?.forEach((wallet) => { result.push({ title: 'Master EOA', - ...getItemData(walletBalances, masterEoaAddress), + ...getBalanceData( + walletBalances.filter((walletBalanceResult) => { + return walletBalanceResult.walletAddress === wallet.address; + }), + ), + address: wallet.address, }); - } + }); - if (masterSafeAddress) { + masterSafes?.forEach((wallet) => { result.push({ title: 'Master Safe', - ...getItemData(walletBalances, masterSafeAddress), + ...getBalanceData( + walletBalances.filter((walletBalanceResult) => { + return walletBalanceResult.walletAddress === wallet.address; + }), + ), + address: wallet.address, + link: { + title: 'Go to Safe', + href: `${EXPLORER_URL[MiddlewareChain.OPTIMISM]}/address/${wallet.address}`, + }, }); - } + }); if (instanceAddress) { result.push({ title: 'Agent Instance EOA', - ...getItemData(walletBalances, instanceAddress!), + ...getBalanceData(walletBalances!), + address: instanceAddress, }); } if (multisigAddress) { result.push({ title: 'Agent Safe', - ...getItemData(walletBalances, multisigAddress), + ...getBalanceData(walletBalances), + address: multisigAddress, }); } return result; }, [ - masterEoaAddress, - masterSafeAddress, instanceAddress, + masterEoas, + masterSafes, multisigAddress, walletBalances, wallets?.length, From f8d8a31f5ec5302ecd7e0a77db30818e281d4c7b Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Wed, 20 Nov 2024 19:04:25 +0100 Subject: [PATCH 283/463] feat/simple backup owner update --- operate/cli.py | 10 +-- operate/services/manage.py | 2 +- operate/utils/gnosis.py | 78 +++++++++++++++++++++-- operate/wallet/master.py | 125 +++++++++++++------------------------ 4 files changed, 125 insertions(+), 90 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index 73ef05353..ea1a3b407 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -516,7 +516,7 @@ async def _create_safe(request: Request) -> t.List[t.Dict]: safes = t.cast(t.Dict[Chain, str], wallet.safes) wallet.create_safe( # pylint: disable=no-member chain=chain, - owner=data.get("owner"), + backup_owner=data.get("backup_owner"), ) wallet.transfer( to=t.cast(str, safes.get(chain)), @@ -582,7 +582,7 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: @app.put("/api/wallet/safe") @with_retries async def _update_safe(request: Request) -> t.List[t.Dict]: - """Create wallet safe""" + """Update wallet safe""" # TODO: Extract login check as decorator if operate.user_account is None: return JSONResponse( @@ -592,7 +592,7 @@ async def _update_safe(request: Request) -> t.List[t.Dict]: if operate.password is None: return JSONResponse( - content={"error": "You need to login before creating a safe"}, + content={"error": "You need to login before updating a safe"}, status_code=401, ) @@ -604,9 +604,9 @@ async def _update_safe(request: Request) -> t.List[t.Dict]: return JSONResponse(content={"error": "Wallet does not exist"}) wallet = manager.load(ledger_type=ledger_type) - wallet.add_or_swap_owner( + wallet.update_backup_owner( chain=chain, - owner=data.get("owner"), + backup_owner=data.get("backup_owner"), ) return JSONResponse(content=wallet.json) diff --git a/operate/services/manage.py b/operate/services/manage.py index 387aabf9e..6164e3010 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -287,7 +287,7 @@ def _deploy_service_onchain( # pylint: disable=too-many-statements,too-many-loc """Deploy as service on-chain""" # TODO This method has not been thoroughly reviewed. Deprecated usage in favour of Safe version. - self.logger.info(f"_deploy_service_onchain_from_safe {chain=}") + self.logger.info(f"_deploy_service_onchain {chain=}") service = self.load(service_config_id=service_config_id) chain_config = service.chain_configs[chain] ledger_config = chain_config.ledger_config diff --git a/operate/utils/gnosis.py b/operate/utils/gnosis.py index 51d8ee58f..7dbf8d9ba 100644 --- a/operate/utils/gnosis.py +++ b/operate/utils/gnosis.py @@ -40,6 +40,7 @@ NULL_ADDRESS: str = "0x" + "0" * 40 MAX_UINT256 = 2**256 - 1 ZERO_ETH = 0 +SENTINEL_OWNERS = "0x0000000000000000000000000000000000000001" class SafeOperation(Enum): @@ -157,7 +158,7 @@ def _get_nonce() -> int: def create_safe( ledger_api: LedgerApi, crypto: Crypto, - owner: t.Optional[str] = None, + backup_owner: t.Optional[str] = None, salt_nonce: t.Optional[int] = None, ) -> t.Tuple[str, int]: """Create gnosis safe.""" @@ -169,7 +170,9 @@ def _build( # pylint: disable=unused-argument tx = registry_contracts.gnosis_safe.get_deploy_transaction( ledger_api=ledger_api, deployer_address=crypto.address, - owners=[crypto.address] if owner is None else [crypto.address, owner], + owners=[crypto.address] + if backup_owner is None + else [crypto.address, backup_owner], threshold=1, salt_nonce=salt_nonce, ) @@ -294,14 +297,81 @@ def add_owner( ) -def swap_owner( # pylint: disable=unused-argument +def get_prev_owner(ledger_api: LedgerApi, safe: str, owner: str) -> str: + """Retrieve the previous owner in the owners list of the Safe.""" + + owners = get_owners(ledger_api=ledger_api, safe=safe) + + try: + index = owners.index(owner) - 1 + except ValueError as e: + raise ValueError( + f"Owner {owner} not found in the owners' list of the Safe." + ) from e + + if index < 0: + return SENTINEL_OWNERS + return owners[index] + + +def swap_owner( ledger_api: LedgerApi, crypto: Crypto, safe: str, old_owner: str, new_owner: str, ) -> None: - """Swap owner on a safe.""" + """Swap owner of a safe.""" + + prev_owner = get_prev_owner(ledger_api=ledger_api, safe=safe, owner=old_owner) + instance = registry_contracts.gnosis_safe.get_instance( + ledger_api=ledger_api, + contract_address=safe, + ) + txd = instance.encodeABI( + fn_name="swapOwner", + args=[ + prev_owner, + old_owner, + new_owner, + ], + ) + send_safe_txs( + txd=bytes.fromhex(txd[2:]), + safe=safe, + ledger_api=ledger_api, + crypto=crypto, + ) + + +def remove_owner( + ledger_api: LedgerApi, + crypto: Crypto, + safe: str, + owner: str, + threshold: int, +) -> None: + """Remove owner from a safe.""" + + prev_owner = get_prev_owner(ledger_api=ledger_api, safe=safe, owner=owner) + instance = registry_contracts.gnosis_safe.get_instance( + ledger_api=ledger_api, + contract_address=safe, + ) + txd = instance.encodeABI( + fn_name="removeOwner", + args=[ + prev_owner, + owner, + threshold, + ], + ) + send_safe_txs( + txd=bytes.fromhex(txd[2:]), + safe=safe, + ledger_api=ledger_api, + crypto=crypto, + ) def transfer( diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 30fd975b6..9e6a856f1 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -130,38 +130,19 @@ def new(password: str, path: Path) -> t.Tuple["MasterWallet", t.List[str]]: def create_safe( self, chain: Chain, - owner: t.Optional[str] = None, + backup_owner: t.Optional[str] = None, rpc: t.Optional[str] = None, ) -> None: """Create safe.""" raise NotImplementedError() - def add_backup_owner( + def update_backup_owner( self, chain: Chain, - owner: str, + backup_owner: t.Optional[str] = None, rpc: t.Optional[str] = None, ) -> None: - """Create safe.""" - raise NotImplementedError() - - def swap_backup_owner( - self, - chain: Chain, - old_owner: str, - new_owner: str, - rpc: t.Optional[str] = None, - ) -> None: - """Create safe.""" - raise NotImplementedError() - - def add_or_swap_owner( - self, - chain: Chain, - owner: str, - rpc: t.Optional[str] = None, - ) -> None: - """Add or swap backup owner.""" + """Update backup owner.""" raise NotImplementedError() @classmethod @@ -333,7 +314,7 @@ def new( def create_safe( self, chain: Chain, - owner: t.Optional[str] = None, + backup_owner: t.Optional[str] = None, rpc: t.Optional[str] = None, ) -> None: """Create safe.""" @@ -342,7 +323,7 @@ def create_safe( safe, self.safe_nonce = create_gnosis_safe( ledger_api=self.ledger_api(chain=chain, rpc=rpc), crypto=self.crypto, - owner=owner, + backup_owner=backup_owner, salt_nonce=self.safe_nonce, ) self.safe_chains.append(chain) @@ -351,75 +332,59 @@ def create_safe( self.safes[chain] = safe self.store() - def add_backup_owner( + def update_backup_owner( self, chain: Chain, - owner: str, + backup_owner: t.Optional[str] = None, rpc: t.Optional[str] = None, ) -> None: - """Add a backup owner.""" + """Adds a backup owner if not present, or updates it by the provided backup owner. Setting a None backup owner will remove the current one, if any.""" ledger_api = self.ledger_api(chain=chain, rpc=rpc) if chain not in self.safes: # type: ignore raise ValueError(f"Safes not created for chain {chain}!") safe = t.cast(str, self.safes[chain]) # type: ignore - if len(get_owners(ledger_api=ledger_api, safe=safe)) == 2: - raise ValueError("Backup owner already exist!") - add_owner( - ledger_api=ledger_api, - safe=safe, - owner=owner, - crypto=self.crypto, - ) + owners = get_owners(ledger_api=ledger_api, safe=safe) - def swap_backup_owner( - self, - chain: Chain, - old_owner: str, - new_owner: str, - rpc: t.Optional[str] = None, - ) -> None: - """Swap backup owner.""" - ledger_api = self.ledger_api(chain=chain, rpc=rpc) - if chain not in self.safes: # type: ignore - raise ValueError(f"Safes not created for chain {chain}!") - safe = t.cast(str, self.safes[chain]) # type: ignore - if len(get_owners(ledger_api=ledger_api, safe=safe)) == 1: - raise ValueError("Backup owner does not exist, cannot swap!") - swap_owner( - ledger_api=ledger_api, - safe=safe, - old_owner=old_owner, - new_owner=new_owner, - crypto=self.crypto, - ) + if len(owners) > 2: + raise RuntimeError(f"Safe {safe} on chain {chain} has more than 2 owners: {owners}.") - def add_or_swap_owner( - self, - chain: Chain, - owner: str, - rpc: t.Optional[str] = None, - ) -> None: - """Add or swap backup owner.""" - ledger_api = self.ledger_api(chain=chain, rpc=rpc) - if self.safes is None or chain not in self.safes: - raise ValueError(f"Safes not created for chain {chain}!") - safe = t.cast(str, self.safes[chain]) - owners = get_owners(ledger_api=ledger_api, safe=safe) - if len(owners) == 1: - return self.add_backup_owner(chain=chain, owner=owner, rpc=rpc) + if backup_owner == safe: + raise ValueError("The Safe address cannot be set as the Safe backup owner.") + + if backup_owner == self.address: + raise ValueError( + "The master wallet cannot be set as the Safe backup owner." + ) owners.remove(self.address) - (old_owner,) = owners - if old_owner == owner: - return None + old_backup_owner = owners[0] if owners else None - return self.swap_backup_owner( - chain=chain, - old_owner=old_owner, - new_owner=owner, - rpc=rpc, - ) + if old_backup_owner == backup_owner: + return + if not old_backup_owner and backup_owner: + add_owner( + ledger_api=ledger_api, + safe=safe, + owner=backup_owner, + crypto=self.crypto, + ) + elif old_backup_owner and not backup_owner: + remove_owner( + ledger_api=ledger_api, + safe=safe, + owner=old_backup_owner, + crypto=self.crypto, + threshold=1, + ) + elif old_backup_owner and backup_owner: + swap_owner( + ledger_api=ledger_api, + safe=safe, + old_owner=old_backup_owner, + new_owner=backup_owner, + crypto=self.crypto, + ) @classmethod def load(cls, path: Path) -> "EthereumMasterWallet": """Load master wallet.""" From bebc919822d589b6996a1c142b904be865a080bf Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:14:45 +0000 Subject: [PATCH 284/463] chore: import updates --- frontend/components/SettingsPage/index.tsx | 6 ++++-- frontend/components/SetupPage/Create/SetupCreateSafe.tsx | 8 ++++---- frontend/components/SetupPage/SetupWelcome.tsx | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/frontend/components/SettingsPage/index.tsx b/frontend/components/SettingsPage/index.tsx index a195f5bd2..e12725c97 100644 --- a/frontend/components/SettingsPage/index.tsx +++ b/frontend/components/SettingsPage/index.tsx @@ -8,9 +8,10 @@ import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { EXPLORER_URL } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; import { SettingsScreen } from '@/enums/SettingsScreen'; -import { useMasterSafe } from '@/hooks/useMasterSafe'; +import { useMultisig } from '@/hooks/useMultisig'; import { usePageState } from '@/hooks/usePageState'; import { useSettings } from '@/hooks/useSettings'; +import { useWalletContext } from '@/hooks/useWallet'; import { truncateAddress } from '@/utils/truncate'; import { CustomAlert } from '../Alert'; @@ -82,7 +83,8 @@ export const Settings = () => { }; const SettingsMain = () => { - const { backupSafeAddress } = useMasterSafe(); + const { wallets } = useWalletContext(); + const { backupSafeAddress } = useMultisig(); const { goto } = usePageState(); const truncatedBackupSafeAddress: string | undefined = useMemo(() => { diff --git a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx index 01988a141..2e16c158f 100644 --- a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx +++ b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx @@ -7,10 +7,10 @@ import { CardSection } from '@/components/styled/CardSection'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { SUPPORT_URL } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; -import { useMasterSafe } from '@/hooks/useMasterSafe'; +import { useMultisig } from '@/hooks/useMultisig'; import { usePageState } from '@/hooks/usePageState'; import { useSetup } from '@/hooks/useSetup'; -import { useWallet } from '@/hooks/useWallet'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { WalletService } from '@/service/Wallet'; import { delayInSeconds } from '@/utils/delay'; @@ -28,8 +28,8 @@ export const SetupCreateSafe = () => { updateWallets, masterSafeAddressKeyExistsForChain, masterSafeAddress, - } = useWallet(); - const { updateMasterSafeOwners } = useMasterSafe(); + } = useMasterWalletContext(); + const { updateMasterSafeOwners } = useMultisig(); const { backupSigner } = useSetup(); const [isCreatingSafe, setIsCreatingSafe] = useState(false); diff --git a/frontend/components/SetupPage/SetupWelcome.tsx b/frontend/components/SetupPage/SetupWelcome.tsx index acf4bef59..f0a8c106e 100644 --- a/frontend/components/SetupPage/SetupWelcome.tsx +++ b/frontend/components/SetupPage/SetupWelcome.tsx @@ -18,7 +18,7 @@ import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { usePageState } from '@/hooks/usePageState'; import { useSetup } from '@/hooks/useSetup'; -import { useWallet } from '@/hooks/useWallet'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { AccountService } from '@/service/Account'; import { FormFlex } from '../styled/FormFlex'; @@ -129,7 +129,7 @@ export const SetupWelcomeLogin = () => { const { goto } = useSetup(); const { goto: gotoPage } = usePageState(); - const { masterSafeAddress, wallets } = useWallet(); + const { masterSafeAddress, wallets } = useMasterWalletContext(); const { isBalanceLoaded, masterEoaBalance: eoaBalance } = useBalanceContext(); const [isLoggingIn, setIsLoggingIn] = useState(false); From 5e7537c7a2712e28aff95534dff2500b6f25a332 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:15:04 +0000 Subject: [PATCH 285/463] chore: change eth balance threshold keys to ChainId --- frontend/constants/thresholds.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/constants/thresholds.ts b/frontend/constants/thresholds.ts index 21cff2570..09d2b0c43 100644 --- a/frontend/constants/thresholds.ts +++ b/frontend/constants/thresholds.ts @@ -1,4 +1,4 @@ -import { MiddlewareChain } from '@/client'; +import { ChainId } from '@/enums/Chain'; /** * @warning must be updated to be dynamic @@ -8,15 +8,15 @@ export const MIN_ETH_BALANCE_THRESHOLDS = { // safeCreation: 1.5, // safeAddSigner: 0.1, // }, - [MiddlewareChain.OPTIMISM]: { + [ChainId.Optimism]: { safeCreation: 0.005, safeAddSigner: 0.005, }, - [MiddlewareChain.ETHEREUM]: { + [ChainId.Ethereum]: { safeCreation: 0.02, safeAddSigner: 0.02, }, - [MiddlewareChain.BASE]: { + [ChainId.Base]: { safeCreation: 0.005, safeAddSigner: 0.005, }, From 1b6dbfb2abb324b51947765e1491f3aa6f1eae36 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:15:15 +0000 Subject: [PATCH 286/463] refactor: update BalanceProvider to use MasterWalletContext for wallet management --- frontend/context/BalanceProvider.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 2eb09d8e8..01f1256a5 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -30,8 +30,8 @@ import { StakedAgentService } from '@/service/agents/StakedAgentService'; import { Address } from '@/types/Address'; import { formatEther } from '@/utils/numberFormatters'; +import { MasterWalletContext } from './MasterWalletProvider'; import { OnlineStatusContext } from './OnlineStatusProvider'; -import { WalletContext } from './WalletProvider'; type CrossChainStakedBalances = Array<{ serviceId: string; @@ -75,7 +75,7 @@ export const BalanceContext = createContext<{ export const BalanceProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); - const { wallets } = useContext(WalletContext); + const { wallets } = useContext(MasterWalletContext); const { services } = useServices(); const [isLoaded, setIsLoaded] = useState(false); From 47ffacf4031bbb41c70c1cd580f4b846a79aed4e Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:15:40 +0000 Subject: [PATCH 287/463] refactor: change Wallet provider to MasterWallet provider (poor naming) --- frontend/context/MasterWalletProvider.tsx | 95 +++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 frontend/context/MasterWalletProvider.tsx diff --git a/frontend/context/MasterWalletProvider.tsx b/frontend/context/MasterWalletProvider.tsx new file mode 100644 index 000000000..63db2c5de --- /dev/null +++ b/frontend/context/MasterWalletProvider.tsx @@ -0,0 +1,95 @@ +import { QueryObserverBaseResult, useQuery } from '@tanstack/react-query'; +import { createContext, PropsWithChildren, useContext, useState } from 'react'; + +import { MiddlewareWalletResponse } from '@/client'; +import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { + MasterEoa, + MasterSafe, + MasterWallets, + WalletOwnerType, + WalletType, +} from '@/enums/Wallet'; +import { UsePause } from '@/hooks/usePause'; +import { WalletService } from '@/service/Wallet'; +import { convertMiddlewareChainToChainId } from '@/utils/middlewareHelpers'; + +import { OnlineStatusContext } from './OnlineStatusProvider'; + +type MasterWalletContext = { + masterEoa?: MasterEoa; + masterSafes?: MasterSafe[]; + wallets?: (MasterEoa | MasterSafe)[]; +} & Partial> & + UsePause; + +export const MasterWalletContext = createContext({ + masterEoa: undefined, + masterSafes: undefined, + wallets: undefined, + paused: false, + setPaused: () => {}, + togglePaused: () => {}, +}); + +const transformMiddlewareWalletResponse = ( + data: MiddlewareWalletResponse, +): MasterWallets => { + const masterEoa: MasterEoa = { + address: data.address, + owner: WalletOwnerType.Master, + type: WalletType.EOA, + }; + + const masterSafes: MasterSafe[] = Object.entries(data.safes).map( + ([middlewareChain, address]) => ({ + address, + chainId: convertMiddlewareChainToChainId(+middlewareChain), + owner: WalletOwnerType.Master, + type: WalletType.Safe, + }), + ); + + return [masterEoa, ...masterSafes]; +}; + +export const MasterWalletProvider = ({ children }: PropsWithChildren) => { + const { isOnline } = useContext(OnlineStatusContext); + + const [paused, setPaused] = useState(false); + + const { data: wallets, refetch } = useQuery({ + queryKey: REACT_QUERY_KEYS.WALLETS_KEY, + queryFn: WalletService.getWallets, + refetchInterval: isOnline && !paused ? FIVE_SECONDS_INTERVAL : false, + select: (data) => transformMiddlewareWalletResponse(data), + }); + + const masterEoa = wallets?.find( + (wallet): wallet is MasterEoa => + wallet.type === WalletType.EOA && wallet.owner === WalletOwnerType.Master, + ); + + const masterSafes = wallets?.filter( + (wallet): wallet is MasterSafe => + wallet.type === WalletType.Safe && + wallet.owner === WalletOwnerType.Master, + ); + + return ( + setPaused((prev) => !prev), + refetch, + }} + > + {children} + + ); +}; From d8137ebb6dd0945c6b356d343b1d986ae9671d40 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:15:50 +0000 Subject: [PATCH 288/463] chore: delete WalletProvider --- frontend/context/WalletProvider.tsx | 78 ----------------------------- 1 file changed, 78 deletions(-) delete mode 100644 frontend/context/WalletProvider.tsx diff --git a/frontend/context/WalletProvider.tsx b/frontend/context/WalletProvider.tsx deleted file mode 100644 index f09260680..000000000 --- a/frontend/context/WalletProvider.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { QueryObserverBaseResult, useQuery } from '@tanstack/react-query'; -import { createContext, PropsWithChildren, useContext, useState } from 'react'; - -import { MiddlewareWalletResponse } from '@/client'; -import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; -import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; -import { - MasterEoa, - MasterSafe, - MasterWallets, - WalletOwnerType, - WalletType, -} from '@/enums/Wallet'; -import { UsePause } from '@/hooks/usePause'; -import { WalletService } from '@/service/Wallet'; -import { convertMiddlewareChainToChainId } from '@/utils/middlewareHelpers'; - -import { OnlineStatusContext } from './OnlineStatusProvider'; - -type WalletContextType = { - wallets?: (MasterEoa | MasterSafe)[]; -} & Partial> & - UsePause; - -export const WalletContext = createContext({ - wallets: undefined, - paused: false, - setPaused: () => {}, - togglePaused: () => {}, -}); - -const transformMiddlewareWalletResponse = ( - data: MiddlewareWalletResponse, -): MasterWallets => { - const masterEoa: MasterEoa = { - address: data.address, - owner: WalletOwnerType.Master, - type: WalletType.EOA, - }; - - const masterSafes: MasterSafe[] = Object.entries(data.safes).map( - ([middlewareChain, address]) => ({ - address, - chainId: convertMiddlewareChainToChainId(+middlewareChain), - owner: WalletOwnerType.Master, - type: WalletType.Safe, - }), - ); - - return [masterEoa, ...masterSafes]; -}; - -export const WalletProvider = ({ children }: PropsWithChildren) => { - const { isOnline } = useContext(OnlineStatusContext); - - const [paused, setPaused] = useState(false); - - const { data: wallets, refetch } = useQuery({ - queryKey: REACT_QUERY_KEYS.WALLETS_KEY, - queryFn: WalletService.getWallets, - refetchInterval: isOnline && !paused ? FIVE_SECONDS_INTERVAL : false, - select: (data) => transformMiddlewareWalletResponse(data), - }); - - return ( - setPaused((prev) => !prev), - refetch, - }} - > - {children} - - ); -}; From 722c110ff776cf374543e0368a1b0c222825b20a Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:16:03 +0000 Subject: [PATCH 289/463] feat: chain name by chainId --- frontend/enums/Chain.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frontend/enums/Chain.ts b/frontend/enums/Chain.ts index 3b4982c7b..4740a6342 100644 --- a/frontend/enums/Chain.ts +++ b/frontend/enums/Chain.ts @@ -4,3 +4,10 @@ export enum ChainId { Gnosis = 10, Base = 8453, } + +export const ChainName = { + [ChainId.Ethereum]: 'Ethereum', + [ChainId.Optimism]: 'Optimism', + [ChainId.Gnosis]: 'Gnosis', + [ChainId.Base]: 'Base', +}; From 76dd098a0fa394591e118a8c4a331d28a1c6f5a4 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:16:25 +0000 Subject: [PATCH 290/463] chore: remove unneeded destructure --- frontend/hooks/useWallet.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/frontend/hooks/useWallet.ts b/frontend/hooks/useWallet.ts index 562d693c9..d3a944baa 100644 --- a/frontend/hooks/useWallet.ts +++ b/frontend/hooks/useWallet.ts @@ -1,10 +1,5 @@ import { useContext } from 'react'; -import { WalletContext } from '@/context/WalletProvider'; +import { MasterWalletContext } from '@/context/MasterWalletProvider'; -export const useWallet = () => { - const { wallets, setPaused, paused, togglePaused, refetch } = - useContext(WalletContext); - - return { wallets, setPaused, paused, togglePaused, refetch }; -}; +export const useMasterWalletContext = () => useContext(MasterWalletContext); From 8e1b388cd4a8aba3098c98ddb5049fe40c74d4d5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:16:38 +0000 Subject: [PATCH 291/463] chore: refactor import names --- frontend/hooks/useLogs.ts | 8 ++++---- frontend/hooks/useService.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index fd0a3d407..2a1936544 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -4,15 +4,15 @@ import { useMemo } from 'react'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { useBalanceContext } from './useBalanceContext'; -import { useMasterSafe } from './useMasterSafe'; +import { useMultisig } from './useMultisig'; import { useServices } from './useServices'; import { useStore } from './useStore'; -import { useWallet } from './useWallet'; +import { useMasterWalletContext } from './useWallet'; const useAddressesLogs = () => { - const { wallets, masterEoaAddress, masterSafeAddress } = useWallet(); + const { wallets, masterEoaAddress, masterSafeAddress } = useMasterWalletContext(); - const { backupSafeAddress, masterSafeOwners } = useMasterSafe(); + const { backupSafeAddress, masterSafeOwners } = useMultisig(); return { isLoaded: wallets?.length !== 0 && !!masterSafeOwners, diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index 27b4c256c..68a9189bb 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -7,7 +7,7 @@ import { WalletOwnerType, WalletType } from '@/enums/Wallet'; import { Address } from '@/types/Address'; import { useServices } from './useServices'; -import { useWallet } from './useWallet'; +import { useMasterWalletContext } from './useWallet'; type ServiceChainIdAddressRecord = { [chainId: number]: { @@ -26,7 +26,7 @@ export const useService = ({ }) => { const { services, isFetched: isLoaded } = useServices(); const queryClient = useQueryClient(); - const { wallets } = useWallet(); + const { wallets } = useMasterWalletContext(); const service = useMemo(() => { return services?.find( From 1aac95f0a18ba0fe1e0b9a8b15f2f3315b970cca Mon Sep 17 00:00:00 2001 From: truemiller Date: Wed, 20 Nov 2024 18:16:58 +0000 Subject: [PATCH 292/463] refactor: update MasterWalletProvider import path --- frontend/pages/_app.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 709e5f2ca..86d81156d 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -8,6 +8,7 @@ import { useEffect, useState } from 'react'; import { Layout } from '@/components/Layout'; import { BalanceProvider } from '@/context/BalanceProvider'; import { ElectronApiProvider } from '@/context/ElectronApiProvider'; +import { MasterWalletProvider } from '@/context/MasterWalletProvider'; import { ModalProvider } from '@/context/ModalProvider'; import { OnlineStatusProvider } from '@/context/OnlineStatusProvider'; import { PageStateProvider } from '@/context/PageStateProvider'; @@ -19,7 +20,6 @@ import { StakingContractDetailsProvider } from '@/context/StakingContractDetails import { StakingProgramProvider } from '@/context/StakingProgramProvider'; import { StoreProvider } from '@/context/StoreProvider'; import { SystemNotificationTriggers } from '@/context/SystemNotificationTriggers'; -import { MasterWalletProvider } from '@/context/WalletProvider'; import { mainTheme } from '@/theme'; import { setupMulticallAddresses } from '@/utils/setupMulticall'; From 9a9f145f218263cafa00d3b2b16ff78656ca538b Mon Sep 17 00:00:00 2001 From: Mohan Date: Thu, 21 Nov 2024 00:45:45 +0530 Subject: [PATCH 293/463] feat: resolve errors to ensure the app runs (part 1) (#466) * feat: update MainPage component to include additional sections and modify staking program ID * feat: simplify staking program handling by removing default program references and enhancing active program logic * feat: add utility functions to assert and ensure non-null values * feat: update NoAvailableSlotsOnTheContract component to display a fallback name for staking program when unavailable * feat: refactor service status handling and update polling interval to use constant * feat: add initial default staking program ID to context and hook * feat: enhance staking contract section to utilize active staking program details * feat: refactor StakingContractTag component and update initial default staking program ID handling * feat: refactor MigrationSuccessModal to use active staking program metadata and improve type definitions * feat: integrate active staking program ID into AgentButton and MainHeader components * Update frontend/components/MainPage/header/index.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * Update frontend/components/MainPage/header/LastTransaction.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * Update frontend/components/ManageStakingPage/StakingContractSection/index.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * Update frontend/hooks/useStakingProgram.ts Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> --------- Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> --- .../header/AgentButton/AgentButton.tsx | 14 ++++- .../components/MainPage/header/AgentHead.tsx | 9 +-- .../header/CannotStartAgentPopover.tsx | 8 +-- .../MainPage/header/LastTransaction.tsx | 15 +++-- frontend/components/MainPage/header/index.tsx | 11 +++- frontend/components/MainPage/index.tsx | 23 ++++---- .../MainPage/modals/MigrationModal.tsx | 27 ++++----- .../NoAvailableSlotsOnTheContract.tsx | 29 ++-------- .../MainPage/sections/GasBalanceSection.tsx | 7 +-- .../StakingContractTag.tsx | 17 ------ .../StakingContractSection/index.tsx | 55 +++++++++++-------- frontend/config/stakingPrograms/index.ts | 8 +++ frontend/constants/intervals.ts | 2 + frontend/context/StakingProgramProvider.tsx | 22 +++++--- frontend/hooks/useStakingProgram.ts | 29 ++++++++-- frontend/types/Util.ts | 35 ++++++++++++ 16 files changed, 188 insertions(+), 123 deletions(-) delete mode 100644 frontend/components/ManageStakingPage/StakingContractSection/StakingContractTag.tsx diff --git a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx index c133e227a..e0fc24a33 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx @@ -5,6 +5,8 @@ import { MiddlewareDeploymentStatus } from '@/client'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useStakingContractDetails } from '@/hooks/useStakingContractDetails'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; +import { assertRequired } from '@/types/Util'; import { CannotStartAgentDueToUnexpectedError, @@ -17,12 +19,22 @@ import { AgentStoppingButton } from './AgentStoppingButton'; export const AgentButton = () => { const { selectedService } = useServices(); + const { activeStakingProgramId } = useStakingProgram(); + const { service, deploymentStatus: serviceStatus, isLoaded, } = useService({ serviceConfigId: selectedService?.service_config_id }); - const { isEligibleForStaking, isAgentEvicted } = useStakingContractDetails(); + + assertRequired( + activeStakingProgramId, + 'Active staking program ID is required', + ); + + const { isEligibleForStaking, isAgentEvicted } = useStakingContractDetails( + activeStakingProgramId, + ); return useMemo(() => { if (!isLoaded) { diff --git a/frontend/components/MainPage/header/AgentHead.tsx b/frontend/components/MainPage/header/AgentHead.tsx index 083f1a47d..bccfc4817 100644 --- a/frontend/components/MainPage/header/AgentHead.tsx +++ b/frontend/components/MainPage/header/AgentHead.tsx @@ -32,17 +32,18 @@ const IdleAgentHead = () => ( ); export const AgentHead = () => { - const { serviceStatus } = useServices(); + const { selectedService } = useServices(); const { isEligibleForRewards } = useReward(); + const status = selectedService?.deploymentStatus; if ( - serviceStatus === MiddlewareDeploymentStatus.DEPLOYING || - serviceStatus === MiddlewareDeploymentStatus.STOPPING + status === MiddlewareDeploymentStatus.DEPLOYING || + status === MiddlewareDeploymentStatus.STOPPING ) { return ; } - if (serviceStatus === MiddlewareDeploymentStatus.DEPLOYED) { + if (status === MiddlewareDeploymentStatus.DEPLOYED) { // If the agent is eligible for rewards, agent is idle return isEligibleForRewards ? : ; } diff --git a/frontend/components/MainPage/header/CannotStartAgentPopover.tsx b/frontend/components/MainPage/header/CannotStartAgentPopover.tsx index 5aa8d37e1..a4ecfe49b 100644 --- a/frontend/components/MainPage/header/CannotStartAgentPopover.tsx +++ b/frontend/components/MainPage/header/CannotStartAgentPopover.tsx @@ -122,15 +122,13 @@ export const CannotStartAgentPopover = () => { const { isAllStakingContractDetailsRecordLoaded } = useStakingContractContext(); - const { activeStakingProgramId, defaultStakingProgramId } = - useStakingProgram(); + const { activeStakingProgramId } = useStakingProgram(); const { isAgentEvicted, isEligibleForStaking } = useActiveStakingContractInfo(); - const { hasEnoughServiceSlots, isRewardsAvailable } = useStakingContractDetails( - activeStakingProgramId ?? defaultStakingProgramId, - ); + const { hasEnoughServiceSlots, isRewardsAvailable } = + useStakingContractDetails(activeStakingProgramId); if (!isAllStakingContractDetailsRecordLoaded) return null; if (isEligibleForStaking) return null; diff --git a/frontend/components/MainPage/header/LastTransaction.tsx b/frontend/components/MainPage/header/LastTransaction.tsx index 9a8a526c2..b90859345 100644 --- a/frontend/components/MainPage/header/LastTransaction.tsx +++ b/frontend/components/MainPage/header/LastTransaction.tsx @@ -4,9 +4,11 @@ import styled from 'styled-components'; import { useInterval } from 'usehooks-ts'; import { MiddlewareChain } from '@/client'; +import { ONE_MINUTE_INTERVAL } from '@/constants/intervals'; import { EXPLORER_URL } from '@/constants/urls'; import { useAddress } from '@/hooks/useAddress'; import { usePageState } from '@/hooks/usePageState'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; import { getLatestTransaction } from '@/service/Ethers'; import { TransactionInfo } from '@/types/TransactionInfo'; import { getTimeAgo } from '@/utils/time'; @@ -22,32 +24,35 @@ const Loader = styled(Skeleton.Input)` } `; -const POLLING_INTERVAL = 60 * 1000; // 1 minute - /** * Displays the last transaction time and link to the transaction on explorer * by agent safe. */ +// TODO: loop over all supported chains export const LastTransaction = () => { const { isPageLoadedAndOneMinutePassed } = usePageState(); const { multisigAddress } = useAddress(); + const { activeStakingProgramMeta } = useStakingProgram(); const [isFetching, setIsFetching] = useState(true); const [transaction, setTransaction] = useState(null); + const chainId = activeStakingProgramMeta?.chainId; + const fetchTransaction = useCallback(async () => { if (!multisigAddress) return; + if (!chainId) return; - getLatestTransaction(multisigAddress) + getLatestTransaction(multisigAddress, chainId) .then((tx) => setTransaction(tx)) .catch((error) => console.error('Failed to get latest transaction', error), ) .finally(() => setIsFetching(false)); - }, [multisigAddress]); + }, [multisigAddress, chainId]); // Poll for the latest transaction - useInterval(() => fetchTransaction(), POLLING_INTERVAL); + useInterval(() => fetchTransaction(), ONE_MINUTE_INTERVAL); // Fetch the latest transaction on mount useEffect(() => { diff --git a/frontend/components/MainPage/header/index.tsx b/frontend/components/MainPage/header/index.tsx index ad87a6564..99afc59f0 100644 --- a/frontend/components/MainPage/header/index.tsx +++ b/frontend/components/MainPage/header/index.tsx @@ -6,6 +6,7 @@ import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; import { FirstRunModal } from '../modals/FirstRunModal'; import { AgentButton } from './AgentButton/AgentButton'; @@ -38,12 +39,20 @@ export const MainHeader = () => { const [isFirstRunModalOpen, setIsFirstRunModalOpen] = useState(false); const handleModalClose = useCallback(() => setIsFirstRunModalOpen(false), []); + const { selectedService } = useServices(); + const configId = selectedService?.service_config_id; + const { isLoaded: isServiceLoaded } = useService({ + serviceConfigId: configId, + }); + const { isActiveStakingProgramLoaded } = useStakingProgram(); + useSetupTrayIcon(); + // TODO: support loading state return ( - + {isServiceLoaded && isActiveStakingProgramLoaded && } ); diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index f1d3bc8d7..0b73d4cd2 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -6,16 +6,15 @@ import { Pages } from '@/enums/Pages'; // import { useMasterSafe } from '@/hooks/useMasterSafe'; import { usePageState } from '@/hooks/usePageState'; -// import { useStakingProgram } from '@/hooks/useStakingProgram'; import { MainHeader } from './header'; import { AddFundsSection } from './sections/AddFundsSection'; -// import { MainNeedsFunds } from './sections/NeedsFundsSection'; +import { AlertSections } from './sections/AlertSections'; +import { GasBalanceSection } from './sections/GasBalanceSection'; +import { KeepAgentRunningSection } from './sections/KeepAgentRunningSection'; +import { MainNeedsFunds } from './sections/NeedsFundsSection'; import { MainOlasBalance } from './sections/OlasBalanceSection'; -// import { AlertSections } from './sections/AlertSections'; -// import { GasBalanceSection } from './sections/GasBalanceSection'; -// import { KeepAgentRunningSection } from './sections/KeepAgentRunningSection'; import { RewardsSection } from './sections/RewardsSection'; -// import { StakingContractUpdate } from './sections/StakingContractUpdate'; +import { StakingContractUpdate } from './sections/StakingContractUpdate'; export const Main = () => { const { goto } = usePageState(); @@ -86,14 +85,14 @@ export const Main = () => { style={{ borderTopColor: 'transparent' }} > - {/* */} + - {/* */} + - {/* */} - {/* */} - {/* */} - {/* */} + + + + diff --git a/frontend/components/MainPage/modals/MigrationModal.tsx b/frontend/components/MainPage/modals/MigrationModal.tsx index ce614e9fb..adda5f200 100644 --- a/frontend/components/MainPage/modals/MigrationModal.tsx +++ b/frontend/components/MainPage/modals/MigrationModal.tsx @@ -1,28 +1,25 @@ import { Button, Flex, Modal, Typography } from 'antd'; import Image from 'next/image'; -import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { MODAL_WIDTH } from '@/constants/width'; import { useStakingProgram } from '@/hooks/useStakingProgram'; +const { Title, Text, Link } = Typography; + +type MigrationModalProps = { open: boolean; onClose: () => void }; export const MigrationSuccessModal = ({ open, onClose, -}: { - open: boolean; - onClose: () => void; -}) => { - const { activeStakingProgramId } = useStakingProgram(); +}: MigrationModalProps) => { + const { activeStakingProgramMeta } = useStakingProgram(); // Close modal if no active staking program, migration doesn't apply to non-stakers - if (!activeStakingProgramId) { + if (!activeStakingProgramMeta) { onClose(); return null; } - const activeStakingProgramMeta = STAKING_PROGRAM_META[activeStakingProgramId]; - return ( - - You switched staking contract succesfully! - - + You switched staking contract successfully! + Your agent is now staked on {activeStakingProgramMeta.name}. - + {/* TODO: Add relevant block explorer domain */} - + View full contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} - + ); diff --git a/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx b/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx index f7de19c59..2037c16db 100644 --- a/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx +++ b/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx @@ -1,7 +1,7 @@ import { Flex, Typography } from 'antd'; -import { useMemo } from 'react'; -import { Pages } from '@/enums/PageState'; +import { NA } from '@/constants/symbols'; +import { Pages } from '@/enums/Pages'; import { usePageState } from '@/hooks/usePageState'; import { useActiveStakingContractInfo, @@ -17,32 +17,15 @@ const { Text } = Typography; export const NoAvailableSlotsOnTheContract = () => { const { goto } = usePageState(); - const { - activeStakingProgramId, - defaultStakingProgramId, - activeStakingProgramMeta, - defaultStakingProgramMeta, - } = useStakingProgram(); + const { activeStakingProgramId, activeStakingProgramMeta } = + useStakingProgram(); const { isAllStakingContractDetailsRecordLoaded } = useStakingContractContext(); const { isServiceStaked } = useActiveStakingContractInfo(); const { hasEnoughServiceSlots } = useStakingContractDetails( - activeStakingProgramId ?? defaultStakingProgramId, - ); - - const stakingProgramName = useMemo(() => { - if (!isAllStakingContractDetailsRecordLoaded) return null; - if (activeStakingProgramId) { - return activeStakingProgramMeta?.name; - } - return defaultStakingProgramMeta?.name; - }, [ activeStakingProgramId, - activeStakingProgramMeta?.name, - defaultStakingProgramMeta?.name, - isAllStakingContractDetailsRecordLoaded, - ]); + ); if (!isAllStakingContractDetailsRecordLoaded) return null; if (hasEnoughServiceSlots) return null; @@ -56,7 +39,7 @@ export const NoAvailableSlotsOnTheContract = () => { message={ - No available staking slots on {stakingProgramName} + No available staking slots on {activeStakingProgramMeta?.name || NA} Select a contract with available slots to start your agent. diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index 9b4249135..bdc62e808 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -100,11 +100,10 @@ const TooltipContent = styled.div` } `; +type GasBalanceSectionProps = { serviceConfigId: string }; export const GasBalanceSection = ({ serviceConfigId, -}: { - serviceConfigId: string; -}) => { +}: GasBalanceSectionProps) => { const { isLoaded } = useBalanceContext(); const { masterSafes } = useService({ serviceConfigId }); @@ -122,7 +121,7 @@ export const GasBalanceSection = ({ title={ Your agent uses this balance to fund trading activity on-chain. - {/* TODO: reintroduce, low prio */} + {/* TODO: reintroduce, low priority */} {/*
{ - if (status === StakingProgramStatus.Active) { - return Active; - } - if (status === StakingProgramStatus.Default) { - return Default; - } - return null; -}; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 65327da57..b23ffea35 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -1,13 +1,10 @@ -import { Flex, theme, Typography } from 'antd'; +import { Flex, Tag, theme, Typography } from 'antd'; import { useMemo } from 'react'; import { MiddlewareChain } from '@/client'; import { CardSection } from '@/components/styled/CardSection'; -import { SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES } from '@/config/olasContracts'; -import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { EXPLORER_URL } from '@/constants/urls'; -import { DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; import { useStakingProgram } from '@/hooks/useStakingProgram'; @@ -16,28 +13,34 @@ import { CantMigrateAlert } from './CantMigrateAlert'; import { MigrateButton } from './MigrateButton'; import { StakingContractDetails } from './StakingContractDetails'; import { StakingContractFundingButton } from './StakingContractFundingButton'; -import { StakingContractTag } from './StakingContractTag'; import { CantMigrateReason, useMigrate } from './useMigrate'; const { Title } = Typography; const { useToken } = theme; +type StakingContractTagProps = { status: StakingProgramStatus | null }; +export const StakingContractTag = ({ status }: StakingContractTagProps) => { + if (status === StakingProgramStatus.Active) { + return Active; + } + if (status === StakingProgramStatus.Default) { + return Default; + } + return null; +}; + type StakingContractSectionProps = { stakingProgramId: StakingProgramId }; export const StakingContractSection = ({ stakingProgramId, }: StakingContractSectionProps) => { - const { activeStakingProgramId } = useStakingProgram(); - const { token } = useToken(); - const { migrateValidation } = useMigrate(stakingProgramId); - - const stakingContractAddress = - SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[ - MiddlewareChain.OPTIMISM - ][stakingProgramId]; - - const stakingProgramMeta = STAKING_PROGRAM_META[stakingProgramId]; + const { + initialDefaultStakingProgramId, + activeStakingProgramId, + activeStakingProgramMeta, + activeStakingProgramAddress, + } = useStakingProgram(); // /** // * Returns `true` if this stakingProgram is active, @@ -50,19 +53,27 @@ export const StakingContractSection = ({ // }, [activeStakingProgramId, defaultStakingProgramId, stakingProgramId]); const contractTagStatus = useMemo(() => { - if (activeStakingProgramId === stakingProgramId) + if (activeStakingProgramId === stakingProgramId) { return StakingProgramStatus.Active; + } // Pearl is not staked, set as Selected if default - if (!activeStakingProgramId && stakingProgramId === defaultStakingProgramId) + if ( + !activeStakingProgramId && + stakingProgramId === initialDefaultStakingProgramId + ) { return StakingProgramStatus.Default; + } // Otherwise, no tag return null; - }, [activeStakingProgramId, defaultStakingProgramId, stakingProgramId]); + }, [ + activeStakingProgramId, + initialDefaultStakingProgramId, + stakingProgramId, + ]); - const showMigrateButton = - stakingProgramId !== (activeStakingProgramId ?? defaultStakingProgramId); + const showMigrateButton = stakingProgramId !== activeStakingProgramId; const showFundingButton = useMemo(() => { if (migrateValidation.canMigrate) return false; @@ -86,14 +97,14 @@ export const StakingContractSection = ({ > - {`${stakingProgramMeta?.name} contract`} + {`${activeStakingProgramMeta?.name} contract`} View contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} diff --git a/frontend/config/stakingPrograms/index.ts b/frontend/config/stakingPrograms/index.ts index a1688303a..735d44e8d 100644 --- a/frontend/config/stakingPrograms/index.ts +++ b/frontend/config/stakingPrograms/index.ts @@ -2,6 +2,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; +import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; import { @@ -46,3 +47,10 @@ export const STAKING_PROGRAM_ADDRESS: { [ChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES, [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, }; + +export const INITIAL_DEFAULT_STAKING_PROGRAM_IDS: { + [chainId: number | ChainId]: StakingProgramId; +} = { + [ChainId.Gnosis]: StakingProgramId.PearlBeta, + [ChainId.Optimism]: StakingProgramId.OptimusAlpha, +}; diff --git a/frontend/constants/intervals.ts b/frontend/constants/intervals.ts index 50afd39d0..0983cbf5d 100644 --- a/frontend/constants/intervals.ts +++ b/frontend/constants/intervals.ts @@ -1 +1,3 @@ +export const ONE_MINUTE_INTERVAL = 60 * 1000; // 1 minute + export const FIVE_SECONDS_INTERVAL = 5000; diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index 3013d7467..ff283dab8 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -1,21 +1,22 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; import { createContext, PropsWithChildren, useCallback } from 'react'; +import { INITIAL_DEFAULT_STAKING_PROGRAM_IDS } from '@/config/stakingPrograms'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useServiceId } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; -import { Nullable } from '@/types/Util'; - -const INITIAL_DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.PearlBeta; +import { Maybe, Nullable } from '@/types/Util'; export const StakingProgramContext = createContext<{ isActiveStakingProgramLoaded: boolean; - activeStakingProgramId: StakingProgramId; + initialDefaultStakingProgramId: Maybe; + activeStakingProgramId: Maybe; }>({ isActiveStakingProgramLoaded: false, - activeStakingProgramId: INITIAL_DEFAULT_STAKING_PROGRAM_ID, + activeStakingProgramId: null, + initialDefaultStakingProgramId: null, }); /** @@ -35,7 +36,10 @@ const useGetActiveStakingProgramId = () => { serviceId!, homeChainId, ); - return response || INITIAL_DEFAULT_STAKING_PROGRAM_ID; + return ( + response || + INITIAL_DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.homeChainId] + ); }, enabled: !!homeChainId && !!serviceId, refetchInterval: serviceId ? FIVE_SECONDS_INTERVAL : false, @@ -64,6 +68,7 @@ const useGetActiveStakingProgramId = () => { * It also provides a method to update the active staking program id in state. */ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { + const { selectedAgentConfig } = useServices(); const { isLoading: isStakingProgramsLoading, data: activeStakingProgramId } = useGetActiveStakingProgramId(); @@ -72,8 +77,9 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { value={{ isActiveStakingProgramLoaded: !isStakingProgramsLoading && !!activeStakingProgramId, - activeStakingProgramId: - activeStakingProgramId || INITIAL_DEFAULT_STAKING_PROGRAM_ID, + activeStakingProgramId, + initialDefaultStakingProgramId: + INITIAL_DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.homeChainId], }} > {children} diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index ab00f7ae2..5da704d74 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -11,19 +11,22 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { useServices } from './useServices'; /** - * Hook to get the active staking program and its metadata. + * Hook to get the staking program and its metadata. */ export const useStakingProgram = () => { - const { isActiveStakingProgramLoaded, activeStakingProgramId } = useContext( - StakingProgramContext, - ); + const { + isActiveStakingProgramLoaded, + activeStakingProgramId, + initialDefaultStakingProgramId, + } = useContext(StakingProgramContext); const { selectedAgentConfig } = useServices(); const { homeChainId } = selectedAgentConfig; const allStakingProgramsKeys = Object.keys(STAKING_PROGRAMS[homeChainId]); const allStakingProgramNameAddressPair = STAKING_PROGRAM_ADDRESS[homeChainId]; - const activeStakingProgramMeta = useMemo(() => { + // TODO: refactor to support allStakingPrograms, previously this was intented solely for the active staking program + const allStakingProgramsMeta = useMemo(() => { if (!isActiveStakingProgramLoaded) return null; if (!activeStakingProgramId) return null; if (activeStakingProgramId.length === 0) return null; @@ -44,6 +47,18 @@ export const useStakingProgram = () => { activeStakingProgramId, ]); + const activeStakingProgramMeta = useMemo(() => { + if (!isActiveStakingProgramLoaded) return null; + if (!activeStakingProgramId) return null; + if (!allStakingProgramsMeta) return null; + + return allStakingProgramsMeta[activeStakingProgramId]; + }, [ + isActiveStakingProgramLoaded, + allStakingProgramsMeta, + activeStakingProgramId, + ]); + const activeStakingProgramAddress = useMemo(() => { if (!activeStakingProgramId) return null; if (activeStakingProgramId.length === 0) return null; @@ -62,6 +77,9 @@ export const useStakingProgram = () => { }, [allStakingProgramNameAddressPair, activeStakingProgramId]); return { + initialDefaultStakingProgramId, + + // active staking program isActiveStakingProgramLoaded, activeStakingProgramId, activeStakingProgramAddress, @@ -70,5 +88,6 @@ export const useStakingProgram = () => { // all staking programs allStakingProgramIds: Object.keys(allStakingProgramNameAddressPair), allStakingProgramAddress: Object.values(allStakingProgramNameAddressPair), + allStakingProgramsMeta, }; }; diff --git a/frontend/types/Util.ts b/frontend/types/Util.ts index 456f55bfc..e4bed10e6 100644 --- a/frontend/types/Util.ts +++ b/frontend/types/Util.ts @@ -3,3 +3,38 @@ export type Nullable = T | null; export type Optional = T | undefined; export type Maybe = Nullable>; + +/** + * function to strip off the null or undefined types from a type by making an assertion. + * @note This function should be used if you are confident that the value will never ever be null or undefined. + * + * @param value Value that should be assumed to be present + * @param reason Reason for the assumption + * @returns void + */ +export function assertRequired( + value: T | null | undefined, + reason: string, +): asserts value is T { + if (value === null || value === undefined) { + throw new Error( + `Failed, value is either null or undefined. Incorrect assumption: ${reason}`, + ); + } +} + +/** + * function to strip off the null or undefined types from a type by making an assertion at runtime. + * @note This function should be used if you are confident that the value will never ever be null or undefined. + * + * @param value Value that should be assumed to be present + * @param reason Reason for the assumption + * @returns `value` that is not null or undefined. + */ +export const ensureRequired = ( + value: T | null | undefined, + why: string, +): T => { + assertRequired(value, why); + return value; +}; From cbafa62d041320e22a62cc61e7b9bf6b7ee97c25 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 05:25:20 +0000 Subject: [PATCH 294/463] refactor: move useAddress hook to backup and update import path --- .../SettingsPage/DebugInfoSection.tsx | 2 +- .../components/YourWalletPage/YourAgent.tsx | 2 +- frontend/hooks/backup/useAddress.ts | 19 +++++++++++++++++++ frontend/hooks/useAddress.ts | 18 ------------------ 4 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 frontend/hooks/backup/useAddress.ts delete mode 100644 frontend/hooks/useAddress.ts diff --git a/frontend/components/SettingsPage/DebugInfoSection.tsx b/frontend/components/SettingsPage/DebugInfoSection.tsx index 3768a94a3..c915d2b99 100644 --- a/frontend/components/SettingsPage/DebugInfoSection.tsx +++ b/frontend/components/SettingsPage/DebugInfoSection.tsx @@ -21,7 +21,7 @@ import { WalletBalanceResult } from '@/context/BalanceProvider'; import { ChainId, ChainName } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; import { WalletType } from '@/enums/Wallet'; -import { useAddress } from '@/hooks/useAddress'; +import { useAddress } from '@/hooks/backup/useAddress'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { Address } from '@/types/Address'; diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index efcd88498..a66d376bb 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components'; import { MiddlewareChain } from '@/client'; import { SERVICE_REGISTRY_L2_CONTRACT_ADDRESS } from '@/config/olasContracts'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { useAddress } from '@/hooks/useAddress'; +import { useAddress } from '@/hooks/backup/useAddress'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useReward } from '@/hooks/useReward'; import { useServices } from '@/hooks/useServices'; diff --git a/frontend/hooks/backup/useAddress.ts b/frontend/hooks/backup/useAddress.ts new file mode 100644 index 000000000..92eab584f --- /dev/null +++ b/frontend/hooks/backup/useAddress.ts @@ -0,0 +1,19 @@ +/** + * @note Access address via wallet or service, relative to current chain, service id + */ + +// const useAddress = () => { +// const { service } = useServices(); + +// /** agent safe multisig address */ +// const multisigAddress = +// service?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data +// ?.multisig; + +// /** agent instance EOA address */ +// const instanceAddress = +// service?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data +// ?.instances?.[0]; + +// return { instanceAddress, multisigAddress }; +// }; diff --git a/frontend/hooks/useAddress.ts b/frontend/hooks/useAddress.ts deleted file mode 100644 index d729957d4..000000000 --- a/frontend/hooks/useAddress.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { CHAIN_CONFIG } from '@/config/chains'; - -import { useServices } from './useServices'; - -export const useAddress = () => { - const { service } = useServices(); - - /** agent safe multisig address */ - const multisigAddress = - service?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data?.multisig; - - /** agent instance EOA address */ - const instanceAddress = - service?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data - ?.instances?.[0]; - - return { instanceAddress, multisigAddress }; -}; From 393b51e40c6ca0e8fa11d99b884bac8374a5acb9 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 05:25:26 +0000 Subject: [PATCH 295/463] feat: add useMultisigs hook to fetch owners from multiple multisigs --- frontend/constants/react-query-keys.ts | 6 ++ frontend/hooks/useMultisig.ts | 81 ++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index aacf5250a..4287debc3 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -65,4 +65,10 @@ export const REACT_QUERY_KEYS = { // multisigs MULTISIG_GET_OWNERS_KEY: (multisig: Safe) => ['multisig', 'getOwners', multisig.chainId, multisig.address] as const, + MULTISIGS_GET_OWNERS_KEY: (multisigs: Safe[]) => + [ + 'multisigs', + 'getOwners', + multisigs.map((multisig) => multisig.address), + ] as const, } as const; diff --git a/frontend/hooks/useMultisig.ts b/frontend/hooks/useMultisig.ts index b9cbaadf6..3793eb5e7 100644 --- a/frontend/hooks/useMultisig.ts +++ b/frontend/hooks/useMultisig.ts @@ -1,5 +1,6 @@ import { useQuery } from '@tanstack/react-query'; import { Contract } from 'ethers'; +import { Contract as MulticallContract, ContractCall } from 'ethers-multicall'; import { GNOSIS_SAFE_ABI } from '@/abis/gnosisSafe'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; @@ -34,3 +35,83 @@ export const useMultisig = (safe: Safe) => { return { owners, ownersIsFetched, ownersIsPending }; }; + +/** + * Hook to fetch from an array of multisigs + */ +export const useMultisigs = (safes: Safe[]) => { + const { + data: owners, + isFetched: ownersIsFetched, + isPending: ownersIsPending, + } = useQuery<{ safeAddress: string; chainId: number; owners: string[] }[]>({ + queryKey: REACT_QUERY_KEYS.MULTISIGS_GET_OWNERS_KEY(safes), + queryFn: async (): Promise< + { + safeAddress: string; + chainId: number; + owners: string[]; + }[] + > => { + const results: { + [chainId: number]: { + safeAddress: string; + contractCall: ContractCall; + }[]; + } = {}; + + // Step 1: Group safes by chainId and prepare contract calls + for (const [chainId] of Object.entries(PROVIDERS)) { + const safesOnChainId = safes.filter( + (safe) => safe.chainId === +chainId, + ); + if (safesOnChainId.length === 0) { + continue; + } + + results[+chainId] = safesOnChainId.map((safe) => ({ + safeAddress: safe.address, + contractCall: new MulticallContract( + safe.address, + GNOSIS_SAFE_ABI, + ).getOwners(), + })); + } + + // Step 2: Execute multicall and gather results + const output: { + safeAddress: string; + chainId: number; + owners: string[]; + }[] = []; + + for (const [chainId, calls] of Object.entries(results)) { + const provider = PROVIDERS[+chainId]?.multicallProvider; + + if (!provider) { + console.error(`No provider found for chainId ${chainId}`); + continue; + } + + // Execute the multicall + const ownersArray = await provider.all( + calls.map((call) => call.contractCall), + ); + + // Combine results into the output + ownersArray.forEach((owners, index) => { + output.push({ + safeAddress: calls[index].safeAddress, + chainId: +chainId, + owners, + }); + }); + } + + return output; + }, + refetchInterval: FIVE_SECONDS_INTERVAL, + }); + + return { owners, ownersIsFetched, ownersIsPending }; +}; From de0a55ef033dd3f13e99af9efe27a67317775b77 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 05:25:31 +0000 Subject: [PATCH 296/463] chore: comment out unused hooks and functions in useLogs for future refactor --- frontend/hooks/useLogs.ts | 178 +++++++++++++++++++------------------- 1 file changed, 90 insertions(+), 88 deletions(-) diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index 2a1936544..ccc7dee46 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -1,101 +1,103 @@ -import { useQueryClient } from '@tanstack/react-query'; -import { useMemo } from 'react'; +// TODO: reintroduce, low prio for refactor -import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +// import { useQueryClient } from '@tanstack/react-query'; +// import { useMemo } from 'react'; -import { useBalanceContext } from './useBalanceContext'; -import { useMultisig } from './useMultisig'; -import { useServices } from './useServices'; -import { useStore } from './useStore'; -import { useMasterWalletContext } from './useWallet'; +// import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; -const useAddressesLogs = () => { - const { wallets, masterEoaAddress, masterSafeAddress } = useMasterWalletContext(); +// import { useBalanceContext } from './useBalanceContext'; +// import { useMultisig } from './useMultisig'; +// import { useServices } from './useServices'; +// import { useStore } from './useStore'; +// import { useMasterWalletContext } from './useWallet'; - const { backupSafeAddress, masterSafeOwners } = useMultisig(); +// const useAddressesLogs = () => { +// const { wallets, masterEoaAddress, masterSafeAddress } = useMasterWalletContext(); - return { - isLoaded: wallets?.length !== 0 && !!masterSafeOwners, - data: [ - { backupSafeAddress: backupSafeAddress ?? 'undefined' }, - { masterSafeAddress: masterSafeAddress ?? 'undefined' }, - { masterEoaAddress: masterEoaAddress ?? 'undefined' }, - { masterSafeOwners: masterSafeOwners ?? 'undefined' }, - ], - }; -}; +// const { backupSafeAddress, masterSafeOwners } = useMultisig(); -const useBalancesLogs = () => { - const { - isBalanceLoaded, - totalEthBalance, - totalOlasBalance, - wallets, - walletBalances, - totalOlasStakedBalance, - } = useBalanceContext(); +// return { +// isLoaded: wallets?.length !== 0 && !!masterSafeOwners, +// data: [ +// { backupSafeAddress: backupSafeAddress ?? 'undefined' }, +// { masterSafeAddress: masterSafeAddress ?? 'undefined' }, +// { masterEoaAddress: masterEoaAddress ?? 'undefined' }, +// { masterSafeOwners: masterSafeOwners ?? 'undefined' }, +// ], +// }; +// }; - return { - isLoaded: isBalanceLoaded, - data: [ - { wallets: wallets ?? 'undefined' }, - { walletBalances: walletBalances ?? 'undefined' }, - { totalOlasStakedBalance: totalOlasStakedBalance ?? 'undefined' }, - { totalEthBalance: totalEthBalance ?? 'undefined' }, - { totalOlasBalance: totalOlasBalance ?? 'undefined' }, - ], - }; -}; +// const useBalancesLogs = () => { +// const { +// isBalanceLoaded, +// totalEthBalance, +// totalOlasBalance, +// wallets, +// walletBalances, +// totalOlasStakedBalance, +// } = useBalanceContext(); -const useServicesLogs = () => { - const { services, isFetched: isLoaded } = useServices(); - const { getQueryData } = useQueryClient(); +// return { +// isLoaded: isBalanceLoaded, +// data: [ +// { wallets: wallets ?? 'undefined' }, +// { walletBalances: walletBalances ?? 'undefined' }, +// { totalOlasStakedBalance: totalOlasStakedBalance ?? 'undefined' }, +// { totalEthBalance: totalEthBalance ?? 'undefined' }, +// { totalOlasBalance: totalOlasBalance ?? 'undefined' }, +// ], +// }; +// }; - return { - isLoaded: isLoaded, - data: { - services: - services?.map((item) => ({ - ...item, - keys: item.keys.map((key) => key.address), - deploymentStatus: getQueryData([ - REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY( - item.service_config_id, - ), - item.service_config_id, - ]), - })) ?? 'undefined', - }, - }; -}; +// const useServicesLogs = () => { +// const { services, isFetched: isLoaded } = useServices(); +// const { getQueryData } = useQueryClient(); -export const useLogs = () => { - const { storeState } = useStore(); +// return { +// isLoaded: isLoaded, +// data: { +// services: +// services?.map((item) => ({ +// ...item, +// keys: item.keys.map((key) => key.address), +// deploymentStatus: getQueryData([ +// REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY( +// item.service_config_id, +// ), +// item.service_config_id, +// ]), +// })) ?? 'undefined', +// }, +// }; +// }; - const { isLoaded: isServicesLoaded, data: services } = useServicesLogs(); - const { isLoaded: isBalancesLoaded, data: balances } = useBalancesLogs(); - const { isLoaded: isAddressesLoaded, data: addresses } = useAddressesLogs(); +// export const useLogs = () => { +// const { storeState } = useStore(); - const logs = useMemo(() => { - if (isServicesLoaded && isBalancesLoaded && isAddressesLoaded) { - return { - store: storeState, - debugData: { - services, - addresses, - balances, - }, - }; - } - }, [ - addresses, - balances, - isAddressesLoaded, - isBalancesLoaded, - isServicesLoaded, - services, - storeState, - ]); +// const { isLoaded: isServicesLoaded, data: services } = useServicesLogs(); +// const { isLoaded: isBalancesLoaded, data: balances } = useBalancesLogs(); +// const { isLoaded: isAddressesLoaded, data: addresses } = useAddressesLogs(); - return logs; -}; +// const logs = useMemo(() => { +// if (isServicesLoaded && isBalancesLoaded && isAddressesLoaded) { +// return { +// store: storeState, +// debugData: { +// services, +// addresses, +// balances, +// }, +// }; +// } +// }, [ +// addresses, +// balances, +// isAddressesLoaded, +// isBalancesLoaded, +// isServicesLoaded, +// services, +// storeState, +// ]); + +// return logs; +// }; From 2cd0db3f061e1bd9810cd98784466e9c004f73a3 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 05:25:41 +0000 Subject: [PATCH 297/463] feat: add masterEoa computation to useService hook for fetching EOA wallets --- frontend/hooks/useService.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index 68a9189bb..e59d9c210 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -3,7 +3,12 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; -import { WalletOwnerType, WalletType } from '@/enums/Wallet'; +import { + MasterEoa, + MasterSafe, + WalletOwnerType, + WalletType, +} from '@/enums/Wallet'; import { Address } from '@/types/Address'; import { useServices } from './useServices'; @@ -72,7 +77,7 @@ export const useService = ({ const masterSafes = useMemo(() => { return ( wallets?.filter( - (wallet) => + (wallet): wallet is MasterSafe => flatAddresses.includes(wallet.address) && wallet.owner === WalletOwnerType.Master && wallet.type === WalletType.Safe, @@ -80,6 +85,17 @@ export const useService = ({ ); }, [flatAddresses, wallets]); + const masterEoa = useMemo(() => { + return ( + wallets?.find( + (wallet): wallet is MasterEoa => + flatAddresses.includes(wallet.address) && + wallet.owner === WalletOwnerType.Master && + wallet.type === WalletType.EOA, + ) ?? null + ); + }, [flatAddresses, wallets]); + /** * Overrides the deployment status of the service in the cache. * @note Overwrite is only temporary if ServicesContext is polling @@ -102,6 +118,7 @@ export const useService = ({ deploymentStatus, setDeploymentStatus, masterSafes, + masterEoa, }; }; From 907c8a6d5a1ca39d16b2a9751b3b689299524c0e Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 06:39:14 +0000 Subject: [PATCH 298/463] feat: add functions to retrieve service templates from SERVICE_TEMPLATES --- frontend/constants/serviceTemplates.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index 9332dd195..f64f7d9cb 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -155,3 +155,10 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ // }, // }, ]; + +export const getServiceTemplates = (): ServiceTemplate[] => SERVICE_TEMPLATES; + +export const getServiceTemplate = ( + templateHash: string, +): ServiceTemplate | undefined => + SERVICE_TEMPLATES.find((template) => template.hash === templateHash); From efcc19bc0e8afc17d36882f6d05d50fb22e6e30a Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 06:39:29 +0000 Subject: [PATCH 299/463] feat: add functions to retrieve native token symbol and ERC20 tokens by chain ID --- frontend/config/tokens.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index 475ce6497..c079e9722 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -130,3 +130,9 @@ export const NATIVE_TOKEN_CONFIG = Object.fromEntries( [tokenSymbol: string]: NativeTokenConfig; }; }; + +export const getNativeTokenSymbol = (chainId: ChainId): TokenSymbol => + Object.keys(NATIVE_TOKEN_CONFIG[chainId])[0] as TokenSymbol; + +export const getErc20s = (chainId: ChainId): Erc20TokenConfig[] => + Object.values(ERC20_TOKEN_CONFIG[chainId]); \ No newline at end of file From dc7b25b5240e60813bfe6093975db51e4a8b17ee Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 06:39:37 +0000 Subject: [PATCH 300/463] feat: add useMasterBalances hook to compute balances for master wallets, EOA, and safes --- frontend/hooks/useBalanceContext.ts | 61 ++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index 1fb72c3bd..aa27d9ea8 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -3,11 +3,17 @@ import { useContext, useMemo } from 'react'; import { BalanceContext, WalletBalanceResult } from '@/context/BalanceProvider'; import { useService } from './useService'; +import { useMasterWalletContext } from './useWallet'; export const useBalanceContext = () => useContext(BalanceContext); +/** + * Balances relevant to a specific service (agent) + * @param serviceConfigId + * @returns + */ export const useServiceBalances = (serviceConfigId: string) => { - const { flatAddresses } = useService({ serviceConfigId }); + const { flatAddresses, masterSafes } = useService({ serviceConfigId }); const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); const serviceWalletBalances = useMemo( @@ -39,7 +45,7 @@ export const useServiceBalances = (serviceConfigId: string) => { const serviceSafeBalances = useMemo( () => walletBalances?.filter((balance) => - flatAddresses.includes(balance.walletAddress), + masterSafes.find(({address}) => balance.walletAddress === address), ), [flatAddresses, walletBalances], ); @@ -52,3 +58,54 @@ export const useServiceBalances = (serviceConfigId: string) => { isLowBalance, }; }; + +/** + * Balances relevant to the master wallets, eoa, and safes + */ +// TODO: complete this hook +export const useMasterBalances = () => { + const { masterSafes, masterEoa } = useMasterWalletContext(); + const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); + + const masterWalletBalances = useMemo( + () => + walletBalances?.filter((balance) => + flatAddresses.includes(balance.walletAddress), + ), + [flatAddresses, walletBalances], + ); + + const masterStakedBalances = useMemo( + () => + stakedBalances?.filter((balance) => + flatAddresses.includes(balance.walletAddress), + ), + [flatAddresses, stakedBalances], + ); + + const masterLowBalances = useMemo( + () => lowBalances?.filter((balance) => balance.walletAddress), + [lowBalances], + ); + + const isLowBalance = useMemo( + () => masterLowBalances?.length > 0, + [masterLowBalances], + ); + + const masterSafeBalances = useMemo( + () => + walletBalances?.filter((balance) => + masterSafes.find(({address}) => balance.walletAddress === address), + ), + [flatAddresses, walletBalances], + ); + + return { + masterWalletBalances, + masterStakedBalances, + masterSafeBalances, + masterLowBalances, + isLowBalance, + }; +}; From 10b5da1c899c576351ece648609f15da469cc305 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 06:39:46 +0000 Subject: [PATCH 301/463] chore: update import statement for useLogs in HelpAndSupportPage component --- frontend/components/Pages/HelpAndSupportPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/Pages/HelpAndSupportPage/index.tsx b/frontend/components/Pages/HelpAndSupportPage/index.tsx index 4e721e047..041f4f490 100644 --- a/frontend/components/Pages/HelpAndSupportPage/index.tsx +++ b/frontend/components/Pages/HelpAndSupportPage/index.tsx @@ -5,8 +5,8 @@ import { useCallback, useEffect, useState } from 'react'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { FAQ_URL, SUPPORT_URL } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; +import { useLogs } from '@/hooks/backup/useLogs'; import { useElectronApi } from '@/hooks/useElectronApi'; -import { useLogs } from '@/hooks/useLogs'; import { usePageState } from '@/hooks/usePageState'; import { CardTitle } from '../../Card/CardTitle'; From 9146e1b0721a30c5eff1a38f85ec0327ab3f4a6a Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 06:39:52 +0000 Subject: [PATCH 302/463] chore: remove unused useLogs hook and related code --- frontend/hooks/useLogs.ts | 103 -------------------------------------- 1 file changed, 103 deletions(-) delete mode 100644 frontend/hooks/useLogs.ts diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts deleted file mode 100644 index ccc7dee46..000000000 --- a/frontend/hooks/useLogs.ts +++ /dev/null @@ -1,103 +0,0 @@ -// TODO: reintroduce, low prio for refactor - -// import { useQueryClient } from '@tanstack/react-query'; -// import { useMemo } from 'react'; - -// import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; - -// import { useBalanceContext } from './useBalanceContext'; -// import { useMultisig } from './useMultisig'; -// import { useServices } from './useServices'; -// import { useStore } from './useStore'; -// import { useMasterWalletContext } from './useWallet'; - -// const useAddressesLogs = () => { -// const { wallets, masterEoaAddress, masterSafeAddress } = useMasterWalletContext(); - -// const { backupSafeAddress, masterSafeOwners } = useMultisig(); - -// return { -// isLoaded: wallets?.length !== 0 && !!masterSafeOwners, -// data: [ -// { backupSafeAddress: backupSafeAddress ?? 'undefined' }, -// { masterSafeAddress: masterSafeAddress ?? 'undefined' }, -// { masterEoaAddress: masterEoaAddress ?? 'undefined' }, -// { masterSafeOwners: masterSafeOwners ?? 'undefined' }, -// ], -// }; -// }; - -// const useBalancesLogs = () => { -// const { -// isBalanceLoaded, -// totalEthBalance, -// totalOlasBalance, -// wallets, -// walletBalances, -// totalOlasStakedBalance, -// } = useBalanceContext(); - -// return { -// isLoaded: isBalanceLoaded, -// data: [ -// { wallets: wallets ?? 'undefined' }, -// { walletBalances: walletBalances ?? 'undefined' }, -// { totalOlasStakedBalance: totalOlasStakedBalance ?? 'undefined' }, -// { totalEthBalance: totalEthBalance ?? 'undefined' }, -// { totalOlasBalance: totalOlasBalance ?? 'undefined' }, -// ], -// }; -// }; - -// const useServicesLogs = () => { -// const { services, isFetched: isLoaded } = useServices(); -// const { getQueryData } = useQueryClient(); - -// return { -// isLoaded: isLoaded, -// data: { -// services: -// services?.map((item) => ({ -// ...item, -// keys: item.keys.map((key) => key.address), -// deploymentStatus: getQueryData([ -// REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY( -// item.service_config_id, -// ), -// item.service_config_id, -// ]), -// })) ?? 'undefined', -// }, -// }; -// }; - -// export const useLogs = () => { -// const { storeState } = useStore(); - -// const { isLoaded: isServicesLoaded, data: services } = useServicesLogs(); -// const { isLoaded: isBalancesLoaded, data: balances } = useBalancesLogs(); -// const { isLoaded: isAddressesLoaded, data: addresses } = useAddressesLogs(); - -// const logs = useMemo(() => { -// if (isServicesLoaded && isBalancesLoaded && isAddressesLoaded) { -// return { -// store: storeState, -// debugData: { -// services, -// addresses, -// balances, -// }, -// }; -// } -// }, [ -// addresses, -// balances, -// isAddressesLoaded, -// isBalancesLoaded, -// isServicesLoaded, -// services, -// storeState, -// ]); - -// return logs; -// }; From 2e2b67e8cceb314209ac90ac0cd14661f93f7cda Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 06:40:08 +0000 Subject: [PATCH 303/463] chore: remove unused useServiceTemplates hook and related code; refactor useNeedsFunds for improved balance handling --- frontend/hooks/backup/useAddress.ts | 4 +- frontend/hooks/backup/useLogs.ts | 103 +++++++++++++++++++++++ frontend/hooks/useNeedsFunds.ts | 116 +++++++++++++++++++------- frontend/hooks/useNotifyOnNewEpoch.ts | 2 +- frontend/hooks/useServiceTemplates.ts | 16 ---- 5 files changed, 193 insertions(+), 48 deletions(-) create mode 100644 frontend/hooks/backup/useLogs.ts delete mode 100644 frontend/hooks/useServiceTemplates.ts diff --git a/frontend/hooks/backup/useAddress.ts b/frontend/hooks/backup/useAddress.ts index 92eab584f..3be5c2626 100644 --- a/frontend/hooks/backup/useAddress.ts +++ b/frontend/hooks/backup/useAddress.ts @@ -1,6 +1,4 @@ -/** - * @note Access address via wallet or service, relative to current chain, service id - */ +// TODO: remove this file, uneccessary // const useAddress = () => { // const { service } = useServices(); diff --git a/frontend/hooks/backup/useLogs.ts b/frontend/hooks/backup/useLogs.ts new file mode 100644 index 000000000..ccc7dee46 --- /dev/null +++ b/frontend/hooks/backup/useLogs.ts @@ -0,0 +1,103 @@ +// TODO: reintroduce, low prio for refactor + +// import { useQueryClient } from '@tanstack/react-query'; +// import { useMemo } from 'react'; + +// import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; + +// import { useBalanceContext } from './useBalanceContext'; +// import { useMultisig } from './useMultisig'; +// import { useServices } from './useServices'; +// import { useStore } from './useStore'; +// import { useMasterWalletContext } from './useWallet'; + +// const useAddressesLogs = () => { +// const { wallets, masterEoaAddress, masterSafeAddress } = useMasterWalletContext(); + +// const { backupSafeAddress, masterSafeOwners } = useMultisig(); + +// return { +// isLoaded: wallets?.length !== 0 && !!masterSafeOwners, +// data: [ +// { backupSafeAddress: backupSafeAddress ?? 'undefined' }, +// { masterSafeAddress: masterSafeAddress ?? 'undefined' }, +// { masterEoaAddress: masterEoaAddress ?? 'undefined' }, +// { masterSafeOwners: masterSafeOwners ?? 'undefined' }, +// ], +// }; +// }; + +// const useBalancesLogs = () => { +// const { +// isBalanceLoaded, +// totalEthBalance, +// totalOlasBalance, +// wallets, +// walletBalances, +// totalOlasStakedBalance, +// } = useBalanceContext(); + +// return { +// isLoaded: isBalanceLoaded, +// data: [ +// { wallets: wallets ?? 'undefined' }, +// { walletBalances: walletBalances ?? 'undefined' }, +// { totalOlasStakedBalance: totalOlasStakedBalance ?? 'undefined' }, +// { totalEthBalance: totalEthBalance ?? 'undefined' }, +// { totalOlasBalance: totalOlasBalance ?? 'undefined' }, +// ], +// }; +// }; + +// const useServicesLogs = () => { +// const { services, isFetched: isLoaded } = useServices(); +// const { getQueryData } = useQueryClient(); + +// return { +// isLoaded: isLoaded, +// data: { +// services: +// services?.map((item) => ({ +// ...item, +// keys: item.keys.map((key) => key.address), +// deploymentStatus: getQueryData([ +// REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY( +// item.service_config_id, +// ), +// item.service_config_id, +// ]), +// })) ?? 'undefined', +// }, +// }; +// }; + +// export const useLogs = () => { +// const { storeState } = useStore(); + +// const { isLoaded: isServicesLoaded, data: services } = useServicesLogs(); +// const { isLoaded: isBalancesLoaded, data: balances } = useBalancesLogs(); +// const { isLoaded: isAddressesLoaded, data: addresses } = useAddressesLogs(); + +// const logs = useMemo(() => { +// if (isServicesLoaded && isBalancesLoaded && isAddressesLoaded) { +// return { +// store: storeState, +// debugData: { +// services, +// addresses, +// balances, +// }, +// }; +// } +// }, [ +// addresses, +// balances, +// isAddressesLoaded, +// isBalancesLoaded, +// isServicesLoaded, +// services, +// storeState, +// ]); + +// return logs; +// }; diff --git a/frontend/hooks/useNeedsFunds.ts b/frontend/hooks/useNeedsFunds.ts index bbe4931dd..fac61fae0 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -1,54 +1,114 @@ -import { formatUnits } from 'ethers/lib/utils'; +import { formatEther, formatUnits } from 'ethers/lib/utils'; import { useMemo } from 'react'; +import { ServiceTemplate } from '@/client'; import { CHAIN_CONFIG } from '@/config/chains'; +import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; +import { getServiceTemplate } from '@/constants/serviceTemplates'; import { useBalanceContext } from './useBalanceContext'; -import { useServiceTemplates } from './useServiceTemplates'; +import { useService } from './useService'; import { useStore } from './useStore'; +import { TokenSymbol } from '@/enums/Token'; +import { getNativeTokenSymbol, NATIVE_TOKEN_CONFIG } from '@/config/tokens'; +import { useMasterWalletContext } from './useWallet'; -export const useNeedsFunds = () => { - const { getServiceTemplates } = useServiceTemplates(); +export const useNeedsFunds = (serviceConfigId: string) => { + const { storeState } = useStore(); + const { service } = useService({ serviceConfigId }); + const { masterSafes } = useMasterWalletContext(); + const { isLoaded: isBalanceLoaded, walletBalances } = + useBalanceContext(); + + + const isInitialFunded = storeState?.isInitialFunded; - const serviceTemplate = useMemo( - () => getServiceTemplates()[0], - [getServiceTemplates], + const serviceTemplate = useMemo( + () => (service ? getServiceTemplate(service.hash) : undefined), + [service], ); - const { storeState } = useStore(); - const isInitialFunded = storeState?.isInitialFunded; + const serviceFundRequirements = useMemo< { + [chainId: number]: { + [tokenSymbol: string]: number; + } + }>(() => { + if (!serviceTemplate) return {}; - const { - isBalanceLoaded, - masterSafeBalance: safeBalance, - totalOlasStakedBalance, - } = useBalanceContext(); - - const serviceFundRequirements = useMemo(() => { - const gasEstimate = - serviceTemplate.configurations[CHAIN_CONFIG.OPTIMISM.chainId] - .monthly_gas_estimate; - const monthlyGasEstimate = Number(formatUnits(`${gasEstimate}`, 18)); - const minimumStakedAmountRequired = - getMinimumStakedAmountRequired(serviceTemplate); - - return { eth: monthlyGasEstimate, olas: minimumStakedAmountRequired }; + const results: { + [chainId: number]: { + [tokenSymbol: string]: number; + } + } = {}; + + Object.entries(serviceTemplate.configurations).forEach( + ([chainId, config]) => { + const serviceTemplateDefault = serviceTemplate.configurations[+chainId].staking_program_id + const serviceCurrent = service?.chain_configs[+chainId]?.chain_data?.user_params?.staking_program_id + + if (!serviceCurrent && !serviceTemplateDefault) return; + + if (!service?.chain_configs[+chainId]) return; + const gasEstimate = config.monthly_gas_estimate; + const monthlyGasEstimate = Number(formatUnits(`${gasEstimate}`, 18)); + const minimumStakedAmountRequired = + STAKING_PROGRAMS[+chainId][ + service?.chain_configs[+chainId]?.chain_data?.user_params + ?.staking_program_id ?? + serviceTemplate.configurations[+chainId].staking_program_id + ].stakingRequirements.OLAS; + + const nativeTokenSymbol = getNativeTokenSymbol(+chainId); + + results[+chainId] = { + [TokenSymbol.OLAS]: +formatEther(minimumStakedAmountRequired), + [nativeTokenSymbol]: +formatEther(monthlyGasEstimate), + // TODO: extend with any further erc20s.. + }; + }, + ); + + return results; }, [serviceTemplate]); const hasEnoughEthForInitialFunding = useMemo( - () => (safeBalance?.ETH || 0) >= (serviceFundRequirements?.eth || 0), - [serviceFundRequirements?.eth, safeBalance], + () => { + if (!serviceFundRequirements) return ; + if (!walletBalances) return ; + + const nativeBalancesByChain = walletBalances.reduce<{[chainId: number]: number}>((acc, {symbol, balance, chainId}) => { + if (getNativeTokenSymbol(chainId) !== symbol) return acc; + + if (!acc[chainId]) acc[chainId] = 0; + acc[chainId] += balance; + + return acc; + }, {}); + + const chainIds = Object.keys(serviceFundRequirements).map(Number); + + return chainIds.every(chainId => { + const nativeTokenSymbol = getNativeTokenSymbol(chainId); + const nativeTokenBalance = nativeBalancesByChain[chainId] || 0; + const nativeTokenRequired = serviceFundRequirements[chainId]?.[nativeTokenSymbol] || 0; + + return nativeTokenBalance >= nativeTokenRequired; + }); + + }, + [], ); + // TODO: refactor this to use the new balance context const hasEnoughOlasForInitialFunding = useMemo(() => { const olasInSafe = safeBalance?.OLAS || 0; - const olasStakedBySafe = totalOlasStakedBalance || 0; + const olasStakedBySafe = totalStakedOlasBalance || 0; const olasRequiredToFundService = serviceFundRequirements.olas || 0; const olasInSafeAndStaked = olasInSafe + olasStakedBySafe; return olasInSafeAndStaked >= olasRequiredToFundService; }, [ safeBalance?.OLAS, - totalOlasStakedBalance, + totalStakedOlasBalance, serviceFundRequirements?.olas, ]); diff --git a/frontend/hooks/useNotifyOnNewEpoch.ts b/frontend/hooks/useNotifyOnNewEpoch.ts index e712e81a7..d3ce826c7 100644 --- a/frontend/hooks/useNotifyOnNewEpoch.ts +++ b/frontend/hooks/useNotifyOnNewEpoch.ts @@ -16,7 +16,7 @@ type EpochStatusNotification = { */ export const useNotifyOnNewEpoch = () => { const { showNotification } = useElectronApi(); - const { isServiceNotRunning } = useServices(); + const { isServiceNotRunning } = useServices(); //TODO: refactor to use single service hook const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded } = useActiveStakingContractInfo(); diff --git a/frontend/hooks/useServiceTemplates.ts b/frontend/hooks/useServiceTemplates.ts deleted file mode 100644 index a3532ddb6..000000000 --- a/frontend/hooks/useServiceTemplates.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ServiceTemplate } from '@/client/types'; -import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; - -export const useServiceTemplates = () => { - const getServiceTemplates = (): ServiceTemplate[] => SERVICE_TEMPLATES; - const getServiceTemplate = ( - templateHash: string, - ): ServiceTemplate | undefined => - SERVICE_TEMPLATES.find((template) => template.hash === templateHash); - - return { - getServiceTemplate, - getServiceTemplates, - serviceTemplate: SERVICE_TEMPLATES[0], // Default to the first template - }; -}; From ca2665856508f033bcb9bc2201ed0e94a4ebe62f Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:04:48 +0000 Subject: [PATCH 304/463] Update frontend/hooks/useBalanceContext.ts --- frontend/hooks/useBalanceContext.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index aa27d9ea8..fbf21b3e0 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -92,7 +92,7 @@ export const useMasterBalances = () => { () => masterLowBalances?.length > 0, [masterLowBalances], ); - +// use flatAddresses for consistency const masterSafeBalances = useMemo( () => walletBalances?.filter((balance) => From 3c6b9d6a21318a6394cade385c5fa719a8f5bdd4 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:19:56 +0000 Subject: [PATCH 305/463] chore: lint fixes, export `masterWallets` to avoid confusion --- .../header/AgentButton/AgentNotRunningButton.tsx | 2 +- .../components/SettingsPage/DebugInfoSection.tsx | 2 +- frontend/components/SetupPage/SetupWelcome.tsx | 2 +- frontend/context/BalanceProvider.tsx | 2 +- frontend/context/MasterWalletProvider.tsx | 12 ++++++------ frontend/hooks/useBalanceContext.ts | 16 ++++++++-------- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index 08dc49255..08c5ce38e 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -27,7 +27,7 @@ import { delayInSeconds } from '@/utils/delay'; /** Button used to start / deploy the agent */ export const AgentNotRunningButton = (serviceConfigId: string) => { - const { wallets } = useMasterWalletContext(); + const { masterWallets: wallets } = useMasterWalletContext(); const { selectedService, setPaused: setIsServicePollingPaused, diff --git a/frontend/components/SettingsPage/DebugInfoSection.tsx b/frontend/components/SettingsPage/DebugInfoSection.tsx index c915d2b99..14d2a7c26 100644 --- a/frontend/components/SettingsPage/DebugInfoSection.tsx +++ b/frontend/components/SettingsPage/DebugInfoSection.tsx @@ -135,7 +135,7 @@ const DebugItem = ({ }; export const DebugInfoSection = () => { - const { wallets } = useMasterWalletContext(); + const { masterWallets: wallets } = useMasterWalletContext(); const { instanceAddress, multisigAddress } = useAddress(); const { walletBalances } = useBalanceContext(); diff --git a/frontend/components/SetupPage/SetupWelcome.tsx b/frontend/components/SetupPage/SetupWelcome.tsx index f0a8c106e..eccd77df3 100644 --- a/frontend/components/SetupPage/SetupWelcome.tsx +++ b/frontend/components/SetupPage/SetupWelcome.tsx @@ -129,7 +129,7 @@ export const SetupWelcomeLogin = () => { const { goto } = useSetup(); const { goto: gotoPage } = usePageState(); - const { masterSafeAddress, wallets } = useMasterWalletContext(); + const { masterSafeAddress, masterWallets: wallets } = useMasterWalletContext(); const { isBalanceLoaded, masterEoaBalance: eoaBalance } = useBalanceContext(); const [isLoggingIn, setIsLoggingIn] = useState(false); diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 01f1256a5..a62682a9f 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -75,7 +75,7 @@ export const BalanceContext = createContext<{ export const BalanceProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); - const { wallets } = useContext(MasterWalletContext); + const { masterWallets: wallets } = useContext(MasterWalletContext); const { services } = useServices(); const [isLoaded, setIsLoaded] = useState(false); diff --git a/frontend/context/MasterWalletProvider.tsx b/frontend/context/MasterWalletProvider.tsx index 63db2c5de..e9a7b2778 100644 --- a/frontend/context/MasterWalletProvider.tsx +++ b/frontend/context/MasterWalletProvider.tsx @@ -20,14 +20,14 @@ import { OnlineStatusContext } from './OnlineStatusProvider'; type MasterWalletContext = { masterEoa?: MasterEoa; masterSafes?: MasterSafe[]; - wallets?: (MasterEoa | MasterSafe)[]; + masterWallets?: (MasterEoa | MasterSafe)[]; } & Partial> & UsePause; export const MasterWalletContext = createContext({ masterEoa: undefined, masterSafes: undefined, - wallets: undefined, + masterWallets: undefined, paused: false, setPaused: () => {}, togglePaused: () => {}, @@ -59,19 +59,19 @@ export const MasterWalletProvider = ({ children }: PropsWithChildren) => { const [paused, setPaused] = useState(false); - const { data: wallets, refetch } = useQuery({ + const { data: masterWallets, refetch } = useQuery({ queryKey: REACT_QUERY_KEYS.WALLETS_KEY, queryFn: WalletService.getWallets, refetchInterval: isOnline && !paused ? FIVE_SECONDS_INTERVAL : false, select: (data) => transformMiddlewareWalletResponse(data), }); - const masterEoa = wallets?.find( + const masterEoa = masterWallets?.find( (wallet): wallet is MasterEoa => wallet.type === WalletType.EOA && wallet.owner === WalletOwnerType.Master, ); - const masterSafes = wallets?.filter( + const masterSafes = masterWallets?.filter( (wallet): wallet is MasterSafe => wallet.type === WalletType.Safe && wallet.owner === WalletOwnerType.Master, @@ -80,7 +80,7 @@ export const MasterWalletProvider = ({ children }: PropsWithChildren) => { return ( useContext(BalanceContext); /** * Balances relevant to a specific service (agent) - * @param serviceConfigId - * @returns + * @param serviceConfigId + * @returns */ export const useServiceBalances = (serviceConfigId: string) => { const { flatAddresses, masterSafes } = useService({ serviceConfigId }); @@ -45,9 +45,9 @@ export const useServiceBalances = (serviceConfigId: string) => { const serviceSafeBalances = useMemo( () => walletBalances?.filter((balance) => - masterSafes.find(({address}) => balance.walletAddress === address), + masterSafes.find(({ address }) => balance.walletAddress === address), ), - [flatAddresses, walletBalances], + [masterSafes, walletBalances], ); return { @@ -72,7 +72,7 @@ export const useMasterBalances = () => { walletBalances?.filter((balance) => flatAddresses.includes(balance.walletAddress), ), - [flatAddresses, walletBalances], + [walletBalances], ); const masterStakedBalances = useMemo( @@ -80,7 +80,7 @@ export const useMasterBalances = () => { stakedBalances?.filter((balance) => flatAddresses.includes(balance.walletAddress), ), - [flatAddresses, stakedBalances], + [stakedBalances], ); const masterLowBalances = useMemo( @@ -92,11 +92,11 @@ export const useMasterBalances = () => { () => masterLowBalances?.length > 0, [masterLowBalances], ); -// use flatAddresses for consistency + // use flatAddresses for consistency const masterSafeBalances = useMemo( () => walletBalances?.filter((balance) => - masterSafes.find(({address}) => balance.walletAddress === address), + masterSafes.find(({ address }) => balance.walletAddress === address), ), [flatAddresses, walletBalances], ); From 095c640191f1893cb5ee9da804908a5d6942704a Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:20:15 +0000 Subject: [PATCH 306/463] fix: useService should only expect service wallets, not master safes/eoas as they're global --- frontend/hooks/useService.ts | 60 ++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index e59d9c210..957058e25 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -3,16 +3,17 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { ChainId } from '@/enums/Chain'; import { - MasterEoa, - MasterSafe, + AgentEoa, + AgentSafe, + AgentWallets, WalletOwnerType, WalletType, } from '@/enums/Wallet'; import { Address } from '@/types/Address'; import { useServices } from './useServices'; -import { useMasterWalletContext } from './useWallet'; type ServiceChainIdAddressRecord = { [chainId: number]: { @@ -31,7 +32,7 @@ export const useService = ({ }) => { const { services, isFetched: isLoaded } = useServices(); const queryClient = useQueryClient(); - const { wallets } = useMasterWalletContext(); + // const { wallets } = useMasterWalletContext(); const service = useMemo(() => { return services?.find( @@ -39,6 +40,33 @@ export const useService = ({ ); }, [serviceConfigId, services]); + const serviceWallets: AgentWallets = useMemo(() => { + if (!service?.chain_configs[ChainId.Gnosis]) return []; + + const chainConfig = service?.chain_configs[ChainId.Gnosis]; + + return [ + ...(chainConfig.chain_data.instances ?? []).map( + (address) => + ({ + address, + owner: WalletOwnerType.Agent, + type: WalletType.EOA, + }) as AgentEoa, + ), + ...(chainConfig.chain_data.multisig + ? [ + { + address: chainConfig.chain_data.multisig, + owner: WalletOwnerType.Agent, + type: WalletType.Safe, + chainId: ChainId.Gnosis, + } as AgentSafe, + ] + : []), + ]; + }, [service]); + const addresses: ServiceChainIdAddressRecord = useMemo(() => { if (!service) return {}; const chainData = service.chain_configs; @@ -74,27 +102,27 @@ export const useService = ({ }, [] as Address[]); }, [addresses]); - const masterSafes = useMemo(() => { + const serviceSafes = useMemo(() => { return ( - wallets?.filter( - (wallet): wallet is MasterSafe => + serviceWallets?.filter( + (wallet): wallet is AgentSafe => flatAddresses.includes(wallet.address) && - wallet.owner === WalletOwnerType.Master && + wallet.owner === WalletOwnerType.Agent && wallet.type === WalletType.Safe, ) ?? [] ); - }, [flatAddresses, wallets]); + }, [flatAddresses, serviceWallets]); - const masterEoa = useMemo(() => { + const serviceEoa = useMemo(() => { return ( - wallets?.find( - (wallet): wallet is MasterEoa => + serviceWallets?.find( + (wallet): wallet is AgentEoa => flatAddresses.includes(wallet.address) && - wallet.owner === WalletOwnerType.Master && + wallet.owner === WalletOwnerType.Agent && wallet.type === WalletType.EOA, ) ?? null ); - }, [flatAddresses, wallets]); + }, [flatAddresses, serviceWallets]); /** * Overrides the deployment status of the service in the cache. @@ -117,8 +145,8 @@ export const useService = ({ isLoaded, deploymentStatus, setDeploymentStatus, - masterSafes, - masterEoa, + masterSafes: serviceSafes, + masterEoa: serviceEoa, }; }; From ac35504f99ca02f7179b5ddb82089ea379292a36 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:32:10 +0000 Subject: [PATCH 307/463] fix: update useMasterBalances to filter balances based on master safes and EOAs --- frontend/hooks/useBalanceContext.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index 9fd28124b..051a20759 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -69,18 +69,20 @@ export const useMasterBalances = () => { const masterWalletBalances = useMemo( () => - walletBalances?.filter((balance) => - flatAddresses.includes(balance.walletAddress), + walletBalances?.filter( + (balance) => + masterSafes?.find((safe) => safe.address === balance.walletAddress) || + masterEoa?.address === balance.walletAddress, ), - [walletBalances], + [masterEoa?.address, masterSafes, walletBalances], ); const masterStakedBalances = useMemo( () => stakedBalances?.filter((balance) => - flatAddresses.includes(balance.walletAddress), + masterSafes?.find((safe) => safe.address === balance.walletAddress), ), - [stakedBalances], + [masterSafes, stakedBalances], ); const masterLowBalances = useMemo( @@ -96,9 +98,9 @@ export const useMasterBalances = () => { const masterSafeBalances = useMemo( () => walletBalances?.filter((balance) => - masterSafes.find(({ address }) => balance.walletAddress === address), + masterSafes?.find(({ address }) => balance.walletAddress === address), ), - [flatAddresses, walletBalances], + [masterSafes, walletBalances], ); return { From 3feb3d41fe4826eac932df2a7245d33aaacdb3d1 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:33:11 +0000 Subject: [PATCH 308/463] docs: add notes to useMasterBalances about master wallets and safes --- frontend/hooks/useBalanceContext.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index 051a20759..9e8362601 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -61,8 +61,9 @@ export const useServiceBalances = (serviceConfigId: string) => { /** * Balances relevant to the master wallets, eoa, and safes + * @note master wallets are *shared* wallets across all services + * @note master safe addresses are deterministic, and should be the same */ -// TODO: complete this hook export const useMasterBalances = () => { const { masterSafes, masterEoa } = useMasterWalletContext(); const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); From 7fb1c99d376f50e956eeafbb65592777cc000c24 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:35:42 +0000 Subject: [PATCH 309/463] fix: add TODO comment for future refactor of serviceWallets logic --- frontend/hooks/useService.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index 957058e25..090dfc628 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -40,6 +40,7 @@ export const useService = ({ ); }, [serviceConfigId, services]); + // TODO: quick hack to fix for refactor (only predict), will make it dynamic later const serviceWallets: AgentWallets = useMemo(() => { if (!service?.chain_configs[ChainId.Gnosis]) return []; From 535a0a6de21f6c722038a439a1abd7f007d58b7b Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:36:28 +0000 Subject: [PATCH 310/463] fix: rename masterSafes to serviceSafes for clarity in useService and related hooks --- frontend/components/MainPage/sections/GasBalanceSection.tsx | 2 +- frontend/hooks/useBalanceContext.ts | 4 +++- frontend/hooks/useService.ts | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index 9b4249135..f42c9c2cc 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -106,7 +106,7 @@ export const GasBalanceSection = ({ serviceConfigId: string; }) => { const { isLoaded } = useBalanceContext(); - const { masterSafes } = useService({ serviceConfigId }); + const { serviceSafes: masterSafes } = useService({ serviceConfigId }); return ( useContext(BalanceContext); * @returns */ export const useServiceBalances = (serviceConfigId: string) => { - const { flatAddresses, masterSafes } = useService({ serviceConfigId }); + const { flatAddresses, serviceSafes: masterSafes } = useService({ + serviceConfigId, + }); const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); const serviceWalletBalances = useMemo( diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index 090dfc628..a8fa5d717 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -146,8 +146,8 @@ export const useService = ({ isLoaded, deploymentStatus, setDeploymentStatus, - masterSafes: serviceSafes, - masterEoa: serviceEoa, + serviceSafes, + serviceEoa, }; }; From 88da4b16a06599e9d34e8b2fd831807ced52903b Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:37:16 +0000 Subject: [PATCH 311/463] fix: remove masterSafes alias in GasBalanceSection and useServiceBalances for clarity --- frontend/components/MainPage/sections/GasBalanceSection.tsx | 4 ++-- frontend/hooks/useBalanceContext.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index f42c9c2cc..a8a019a64 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -106,7 +106,7 @@ export const GasBalanceSection = ({ serviceConfigId: string; }) => { const { isLoaded } = useBalanceContext(); - const { serviceSafes: masterSafes } = useService({ serviceConfigId }); + const { serviceSafes } = useService({ serviceConfigId }); return ( Trading balance  - {masterSafes.length > 0 && ( + {serviceSafes.length > 0 && ( diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index 0a4f99005..51392983e 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -13,7 +13,7 @@ export const useBalanceContext = () => useContext(BalanceContext); * @returns */ export const useServiceBalances = (serviceConfigId: string) => { - const { flatAddresses, serviceSafes: masterSafes } = useService({ + const { flatAddresses, serviceSafes } = useService({ serviceConfigId, }); const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); @@ -47,9 +47,9 @@ export const useServiceBalances = (serviceConfigId: string) => { const serviceSafeBalances = useMemo( () => walletBalances?.filter((balance) => - masterSafes.find(({ address }) => balance.walletAddress === address), + serviceSafes.find(({ address }) => balance.walletAddress === address), ), - [masterSafes, walletBalances], + [serviceSafes, walletBalances], ); return { From 8c9ca07a17a91fd1bb54c410e76ecdcfc27ab676 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:39:12 +0000 Subject: [PATCH 312/463] chore: lint fix --- .../components/MainPage/header/CannotStartAgentPopover.tsx | 7 ++++--- .../ManageStakingPage/StakingContractSection/index.tsx | 1 - frontend/components/SetupPage/SetupWelcome.tsx | 3 ++- frontend/components/YourWalletPage/YourAgent.tsx | 3 ++- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/frontend/components/MainPage/header/CannotStartAgentPopover.tsx b/frontend/components/MainPage/header/CannotStartAgentPopover.tsx index 5aa8d37e1..58d4b8ce4 100644 --- a/frontend/components/MainPage/header/CannotStartAgentPopover.tsx +++ b/frontend/components/MainPage/header/CannotStartAgentPopover.tsx @@ -128,9 +128,10 @@ export const CannotStartAgentPopover = () => { const { isAgentEvicted, isEligibleForStaking } = useActiveStakingContractInfo(); - const { hasEnoughServiceSlots, isRewardsAvailable } = useStakingContractDetails( - activeStakingProgramId ?? defaultStakingProgramId, - ); + const { hasEnoughServiceSlots, isRewardsAvailable } = + useStakingContractDetails( + activeStakingProgramId ?? defaultStakingProgramId, + ); if (!isAllStakingContractDetailsRecordLoaded) return null; if (isEligibleForStaking) return null; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 65327da57..117e56913 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -7,7 +7,6 @@ import { SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES } from '@/config/ol import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { EXPLORER_URL } from '@/constants/urls'; -import { DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; import { useStakingProgram } from '@/hooks/useStakingProgram'; diff --git a/frontend/components/SetupPage/SetupWelcome.tsx b/frontend/components/SetupPage/SetupWelcome.tsx index eccd77df3..789501cf4 100644 --- a/frontend/components/SetupPage/SetupWelcome.tsx +++ b/frontend/components/SetupPage/SetupWelcome.tsx @@ -129,7 +129,8 @@ export const SetupWelcomeLogin = () => { const { goto } = useSetup(); const { goto: gotoPage } = usePageState(); - const { masterSafeAddress, masterWallets: wallets } = useMasterWalletContext(); + const { masterSafeAddress, masterWallets: wallets } = + useMasterWalletContext(); const { isBalanceLoaded, masterEoaBalance: eoaBalance } = useBalanceContext(); const [isLoggingIn, setIsLoggingIn] = useState(false); diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index a66d376bb..c0923e2ee 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -149,7 +149,8 @@ const ServiceAndNftDetails = () => { }; export const YourAgentWallet = () => { - const { isBalanceLoaded, agentSafeBalance, agentEoaBalance } = useBalanceContext(); + const { isBalanceLoaded, agentSafeBalance, agentEoaBalance } = + useBalanceContext(); const { availableRewardsForEpochEth, isEligibleForRewards, From 0f16cb877d4048f0e4451b6734802dddc38d5ce2 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 11:44:35 +0000 Subject: [PATCH 313/463] fix: temporarily disable environment validation during refactor --- electron/main.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/electron/main.js b/electron/main.js index e08ab15a1..be2c0de11 100644 --- a/electron/main.js +++ b/electron/main.js @@ -29,7 +29,8 @@ const { PearlTray } = require('./components/PearlTray'); // Validates environment variables required for Pearl // kills the app/process if required environment variables are unavailable // mostly RPC URLs and NODE_ENV -validateEnv(); +// TODO: only reintroduce once refactor completed +// validateEnv(); // Attempt to acquire the single instance lock const singleInstanceLock = app.requestSingleInstanceLock(); From 3967b51efdc3b1fb78d2dbcfaf836aba8fea06c0 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 12:21:12 +0000 Subject: [PATCH 314/463] fix: enhance useServiceBalances to include service EOA and improve balance calculations --- frontend/hooks/useBalanceContext.ts | 44 ++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index 51392983e..f9d72b993 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -12,20 +12,15 @@ export const useBalanceContext = () => useContext(BalanceContext); * @param serviceConfigId * @returns */ -export const useServiceBalances = (serviceConfigId: string) => { - const { flatAddresses, serviceSafes } = useService({ +export const useServiceBalances = (serviceConfigId: string | undefined) => { + const { flatAddresses, serviceSafes, serviceEoa } = useService({ serviceConfigId, }); const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); - const serviceWalletBalances = useMemo( - () => - walletBalances?.filter((balance) => - flatAddresses.includes(balance.walletAddress), - ), - [flatAddresses, walletBalances], - ); - + /** + * Staked balances, only relevant to safes + */ const serviceStakedBalances = useMemo( () => stakedBalances?.filter((balance) => @@ -34,16 +29,23 @@ export const useServiceBalances = (serviceConfigId: string) => { [flatAddresses, stakedBalances], ); + /** Array of cross-chain wallet balances relevant to the service with is considered low */ const serviceLowBalances = useMemo( () => lowBalances?.filter((balance) => balance.walletAddress), [lowBalances], ); + /** + * Boolean indicating if the service has low balances + */ const isLowBalance = useMemo( () => serviceLowBalances?.length > 0, [serviceLowBalances], ); + /** + * Cross-chain unstaked balances in service safes + */ const serviceSafeBalances = useMemo( () => walletBalances?.filter((balance) => @@ -52,10 +54,32 @@ export const useServiceBalances = (serviceConfigId: string) => { [serviceSafes, walletBalances], ); + /** + * Cross-chain unstaked balances in service eoa (signer) + */ + const serviceEoaBalances = useMemo( + () => + walletBalances?.filter( + (balance) => balance.walletAddress === serviceEoa?.address, + ), + [serviceEoa?.address, walletBalances], + ); + + /** + * Balances i.e. native, erc20, etc + * Across all service wallets, including eoa + * @note NOT STAKED BALANCES + */ + const serviceWalletBalances = useMemo( + () => [...serviceSafeBalances, ...serviceEoaBalances], + [serviceEoaBalances, serviceSafeBalances], + ); + return { serviceWalletBalances, serviceStakedBalances, serviceSafeBalances, + serviceEoaBalances, serviceLowBalances, isLowBalance, }; From 209fa1de72646602c4c3fa16ae95d7eb01f5dea5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 12:30:51 +0000 Subject: [PATCH 315/463] refactor: simplify balance calculations and add master EOA balances --- frontend/hooks/useBalanceContext.ts | 49 ++++++++++++++++++----------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index f9d72b993..c2d7a080f 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -94,24 +94,18 @@ export const useMasterBalances = () => { const { masterSafes, masterEoa } = useMasterWalletContext(); const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); - const masterWalletBalances = useMemo( - () => - walletBalances?.filter( - (balance) => - masterSafes?.find((safe) => safe.address === balance.walletAddress) || - masterEoa?.address === balance.walletAddress, - ), - [masterEoa?.address, masterSafes, walletBalances], - ); - - const masterStakedBalances = useMemo( - () => - stakedBalances?.filter((balance) => - masterSafes?.find((safe) => safe.address === balance.walletAddress), - ), - [masterSafes, stakedBalances], - ); + // TODO: unused, check only services stake? + // const masterStakedBalances = useMemo( + // () => + // stakedBalances?.filter((balance) => + // masterSafes?.find((safe) => safe.address === balance.walletAddress), + // ), + // [masterSafes, stakedBalances], + // ); + /** + * Array of low balances relevant to the master wallets (safes and eoa) + */ const masterLowBalances = useMemo( () => lowBalances?.filter((balance) => balance.walletAddress), [lowBalances], @@ -121,7 +115,8 @@ export const useMasterBalances = () => { () => masterLowBalances?.length > 0, [masterLowBalances], ); - // use flatAddresses for consistency + + // TODO: use flatAddresses for consistency const masterSafeBalances = useMemo( () => walletBalances?.filter((balance) => @@ -130,10 +125,26 @@ export const useMasterBalances = () => { [masterSafes, walletBalances], ); + const masterEoaBalances = useMemo( + () => + walletBalances?.filter( + (balance) => balance.walletAddress === masterEoa?.address, + ), + [masterEoa?.address, walletBalances], + ); + + /** + * Unstaked balances across master safes and eoas + */ + const masterWalletBalances = useMemo( + () => [...masterSafeBalances, ...masterEoaBalances], + [masterEoaBalances, masterSafeBalances], + ); + return { masterWalletBalances, - masterStakedBalances, masterSafeBalances, + masterEoaBalances, masterLowBalances, isLowBalance, }; From a9274263ccc9d40af3401598eddb9b81bbe5015f Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 12:38:15 +0000 Subject: [PATCH 316/463] feat: enhance OLAS balance calculations by integrating master and service wallet balances --- .../MainPage/sections/OlasBalanceSection.tsx | 57 +++++++++++++++++-- 1 file changed, 51 insertions(+), 6 deletions(-) diff --git a/frontend/components/MainPage/sections/OlasBalanceSection.tsx b/frontend/components/MainPage/sections/OlasBalanceSection.tsx index 1132bd5a0..5a7ca8aed 100644 --- a/frontend/components/MainPage/sections/OlasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/OlasBalanceSection.tsx @@ -4,8 +4,14 @@ import { useMemo } from 'react'; import styled from 'styled-components'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { TokenSymbol } from '@/enums/Token'; // import { Pages } from '@/enums/PageState'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { + useBalanceContext, + useMasterBalances, + useServiceBalances, +} from '@/hooks/useBalanceContext'; +import { useServices } from '@/hooks/useServices'; // import { usePageState } from '@/hooks/usePageState'; import { balanceFormat } from '@/utils/numberFormatters'; @@ -22,13 +28,52 @@ type MainOlasBalanceProps = { isBorderTopVisible?: boolean }; export const MainOlasBalance = ({ isBorderTopVisible = true, }: MainOlasBalanceProps) => { - const { isLoaded: isBalanceLoaded, totalOlasBalance } = useBalanceContext(); + const { selectedService } = useServices(); + const { isLoaded: isBalanceLoaded } = useBalanceContext(); + const { masterWalletBalances } = useMasterBalances(); + const { serviceStakedBalances, serviceWalletBalances } = useServiceBalances( + selectedService?.service_config_id, + ); // const { goto } = usePageState(); - const balance = useMemo(() => { - if (totalOlasBalance === undefined) return '--'; + const displayedBalance = useMemo(() => { + // olas across master wallets, safes and eoa + const masterWalletOlasBalance = masterWalletBalances?.reduce( + (acc, { symbol, balance }) => { + if (symbol === TokenSymbol.OLAS) { + return acc + Number(balance); + } + return acc; + }, + 0, + ); + + // olas across all service wallets + const serviceWalletOlasBalance = serviceWalletBalances?.reduce( + (acc, { symbol, balance }) => { + if (symbol === TokenSymbol.OLAS) { + return acc + Number(balance); + } + return acc; + }, + 0, + ); + + // olas staked across all services + const serviceStakedOlasBalance = serviceStakedBalances?.reduce( + (acc, { olasBondBalance, olasDepositBalance }) => { + return acc + Number(olasBondBalance) + Number(olasDepositBalance); + }, + 0, + ); + + const totalOlasBalance = + masterWalletOlasBalance + + serviceWalletOlasBalance + + serviceStakedOlasBalance; + return balanceFormat(totalOlasBalance, 2); - }, [totalOlasBalance]); + }, [masterWalletBalances, serviceStakedBalances, serviceWalletBalances]); return ( Current balance {UNICODE_SYMBOLS.OLAS} - {balance} + {displayedBalance} OLAS From c5388ad3ea965459618e0051c9f09adff5e86c44 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 12:38:35 +0000 Subject: [PATCH 317/463] fix: remove unused masterStakedBalances from useMasterBalances function --- frontend/hooks/useBalanceContext.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index c2d7a080f..0ecad8c98 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -92,7 +92,7 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { */ export const useMasterBalances = () => { const { masterSafes, masterEoa } = useMasterWalletContext(); - const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); + const { walletBalances, lowBalances } = useBalanceContext(); // TODO: unused, check only services stake? // const masterStakedBalances = useMemo( From 30d0a8a560f3718a338312e45276ee8a2eeca11e Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 12:39:01 +0000 Subject: [PATCH 318/463] refactor: reorganize low balance calculations in useMasterBalances for clarity --- frontend/hooks/useBalanceContext.ts | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index 0ecad8c98..5a7f744f3 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -103,19 +103,6 @@ export const useMasterBalances = () => { // [masterSafes, stakedBalances], // ); - /** - * Array of low balances relevant to the master wallets (safes and eoa) - */ - const masterLowBalances = useMemo( - () => lowBalances?.filter((balance) => balance.walletAddress), - [lowBalances], - ); - - const isLowBalance = useMemo( - () => masterLowBalances?.length > 0, - [masterLowBalances], - ); - // TODO: use flatAddresses for consistency const masterSafeBalances = useMemo( () => @@ -141,6 +128,22 @@ export const useMasterBalances = () => { [masterEoaBalances, masterSafeBalances], ); + /** + * Array of low balances relevant to the master wallets (safes and eoa) + */ + const masterLowBalances = useMemo( + () => lowBalances?.filter((balance) => balance.walletAddress), + [lowBalances], + ); + + /** + * Boolean indicating if any master wallets have low balances + */ + const isLowBalance = useMemo( + () => masterLowBalances?.length > 0, + [masterLowBalances], + ); + return { masterWalletBalances, masterSafeBalances, From c64eceed2a46a611e02938d1beeda5276bd0855b Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 14:00:14 +0000 Subject: [PATCH 319/463] fix: comment out duplicate MainOlasBalance component in MainPage for clarity --- frontend/components/MainPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index 0b73d4cd2..7e444272d 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -87,7 +87,7 @@ export const Main = () => { - + {/* */} From 2baf40ca4b36c35628f7cb5da78091845ed7ba5e Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 14:00:39 +0000 Subject: [PATCH 320/463] fix: comment out GasBalanceSection in MainPage for clarity --- frontend/components/MainPage/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index 7e444272d..240009ef1 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -9,7 +9,6 @@ import { usePageState } from '@/hooks/usePageState'; import { MainHeader } from './header'; import { AddFundsSection } from './sections/AddFundsSection'; import { AlertSections } from './sections/AlertSections'; -import { GasBalanceSection } from './sections/GasBalanceSection'; import { KeepAgentRunningSection } from './sections/KeepAgentRunningSection'; import { MainNeedsFunds } from './sections/NeedsFundsSection'; import { MainOlasBalance } from './sections/OlasBalanceSection'; @@ -91,7 +90,7 @@ export const Main = () => { - + {/* */} From cd3aacb3bf04100e32d1f16901c305bf67c18259 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 14:33:56 +0000 Subject: [PATCH 321/463] feat: add agenttype to service templates --- frontend/client/types.ts | 2 ++ frontend/constants/serviceTemplates.ts | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/client/types.ts b/frontend/client/types.ts index 7f09e8b9d..15aae6625 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -1,3 +1,4 @@ +import { AgentType } from '@/enums/Agent'; import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; @@ -70,6 +71,7 @@ export type EnvVariableAttributes = { }; export type ServiceTemplate = { + agentType: AgentType; name: string; hash: string; description: string; diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index f64f7d9cb..987c6a973 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -1,9 +1,11 @@ import { EnvProvisionType, ServiceTemplate } from '@/client'; +import { AgentType } from '@/enums/Agent'; import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; export const SERVICE_TEMPLATES: ServiceTemplate[] = [ { + agentType: AgentType.PredictTrader, // TODO: remove if causes errors on middleware name: 'Trader Agent', hash: 'bafybeidicxsruh3r4a2xarawzan6ocwyvpn3ofv42po5kxf7x6ck7kn22u', description: 'Trader agent for omen prediction markets', @@ -15,7 +17,7 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ [ChainId.Gnosis]: { staking_program_id: StakingProgramId.PearlBeta, // default, may be overwritten nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', - rpc: 'http://localhost:8545', + rpc: 'http://localhost:8545', // overwritten agent_id: 14, threshold: 1, use_staking: true, From 33a50972f8f20188895878c85d39e130143ef4bb Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 14:34:14 +0000 Subject: [PATCH 322/463] feat: add mechType to GNOSIS staking programs configuration --- frontend/config/stakingPrograms/gnosis.ts | 7 +++++++ frontend/config/stakingPrograms/index.ts | 2 ++ 2 files changed, 9 insertions(+) diff --git a/frontend/config/stakingPrograms/gnosis.ts b/frontend/config/stakingPrograms/gnosis.ts index d53dd3349..e2a8361eb 100644 --- a/frontend/config/stakingPrograms/gnosis.ts +++ b/frontend/config/stakingPrograms/gnosis.ts @@ -34,6 +34,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { stakingRequirements: { [TokenSymbol.OLAS]: 20, }, + mechType: MechType.Agent, mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( @@ -48,6 +49,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { stakingRequirements: { [TokenSymbol.OLAS]: 40, }, + mechType: MechType.Agent, mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( @@ -62,6 +64,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { stakingRequirements: { [TokenSymbol.OLAS]: 100, }, + mechType: MechType.Agent, mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( @@ -76,6 +79,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { stakingRequirements: { [TokenSymbol.OLAS]: 100, }, + mechType: MechType.Agent, mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( @@ -90,6 +94,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { stakingRequirements: { [TokenSymbol.OLAS]: 100, }, + mechType: MechType.Agent, mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( @@ -104,6 +109,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { stakingRequirements: { [TokenSymbol.OLAS]: 10, }, + mechType: MechType.Agent, mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], contract: new MulticallContract( @@ -118,6 +124,7 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { stakingRequirements: { [TokenSymbol.OLAS]: 40, }, + mechType: MechType.Marketplace, mech: MECHS[ChainId.Gnosis][MechType.Marketplace].contract, activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Marketplace], contract: new MulticallContract( diff --git a/frontend/config/stakingPrograms/index.ts b/frontend/config/stakingPrograms/index.ts index 735d44e8d..8c4be8c60 100644 --- a/frontend/config/stakingPrograms/index.ts +++ b/frontend/config/stakingPrograms/index.ts @@ -5,6 +5,7 @@ import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; +import { MechType } from '../mechs'; import { GNOSIS_STAKING_PROGRAMS, GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES, @@ -26,6 +27,7 @@ export type StakingProgramConfig = { [tokenSymbol: string]: number; }; contract: MulticallContract; + mechType?: MechType; mech?: MulticallContract; activityChecker: MulticallContract; }; From 699660bbb5dc3dd9dee678ac2a26fe3c3ac531de Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 14:34:46 +0000 Subject: [PATCH 323/463] feat: enhance useActiveStakingContractInfo with service staking state and additional return values --- frontend/hooks/useStakingContractDetails.ts | 22 ++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/frontend/hooks/useStakingContractDetails.ts b/frontend/hooks/useStakingContractDetails.ts index b5b01915b..41a8b34ac 100644 --- a/frontend/hooks/useStakingContractDetails.ts +++ b/frontend/hooks/useStakingContractDetails.ts @@ -3,6 +3,7 @@ import { useContext } from 'react'; import { StakingContractDetailsContext } from '@/context/StakingContractDetailsProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; +import { ServiceStakingState } from '@/types/Autonolas'; import { useServices } from './useServices'; @@ -27,10 +28,20 @@ export const useStakingContractContext = () => { }; }; +/** + * Returns ACTIVE staking contract details + * Has staked service speficic information that `useStakingContractDetails` does not have + + * @note requires serviceConfigId once multiple instances are supported + */ export const useActiveStakingContractInfo = () => { const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded: isActiveStakingContractDetailsLoaded, + allStakingContractDetailsRecord, + refetchActiveStakingContractDetails, + isPaused, + setIsPaused, } = useStakingContractContext(); const { selectedService } = useServices(); @@ -40,8 +51,8 @@ export const useActiveStakingContractInfo = () => { return { allStakingContractDetailsRecord, refetchActiveStakingContractDetails, - setIsPaused, isPaused, + setIsPaused, }; } @@ -54,10 +65,12 @@ export const useActiveStakingContractInfo = () => { maxNumServices, } = activeStakingContractDetails ?? {}; - const isAgentEvicted = serviceStakingState === 2; + const isAgentEvicted = + serviceStakingState === ServiceStakingState.EvictedOrUnstaked; const isServiceStaked = - !!serviceStakingStartTime && serviceStakingState === 1; + !!serviceStakingStartTime && + serviceStakingState === ServiceStakingState.Staked; const isRewardsAvailable = availableRewards ?? 0 > 0; @@ -102,6 +115,9 @@ export const useActiveStakingContractInfo = () => { evictionExpiresAt, isActiveStakingContractDetailsLoaded, activeStakingContractDetails, + hasEnoughRewardsAndSlots, + hasEnoughServiceSlots, + isRewardsAvailable, }; }; From f38092b0b2215030f9ce530612e21ad0ba0a68c0 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 14:34:58 +0000 Subject: [PATCH 324/463] feat: add ServiceStakingState enum to improve clarity of staking states --- frontend/types/Autonolas.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/types/Autonolas.ts b/frontend/types/Autonolas.ts index fe1695d9f..2c0e3fefe 100644 --- a/frontend/types/Autonolas.ts +++ b/frontend/types/Autonolas.ts @@ -14,6 +14,12 @@ export const StakingRewardsInfoSchema = z.object({ export type StakingRewardsInfo = z.infer; +export enum ServiceStakingState { + NotStaked = 0, + Staked = 1, + EvictedOrUnstaked = 2, +} + export type StakingContractDetails = { availableRewards: number; /* number of slots available for staking */ @@ -24,7 +30,7 @@ export type StakingContractDetails = { /** time when service was staked (in seconds) - 0 = never staked */ serviceStakingStartTime: number; /** 0: not staked, 1: staked, 2: unstaked - current state of the service */ - serviceStakingState: number; + serviceStakingState: ServiceStakingState; /** OLAS cost of staking */ minStakingDeposit: number; /** estimated annual percentage yield */ From 9b325dde59d42b5bb53712238ac04787c86cf673 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 14:35:04 +0000 Subject: [PATCH 325/463] feat: refactor AgentButton and AgentNotRunningButton to use useActiveStakingContractInfo for improved clarity and functionality --- .../header/AgentButton/AgentButton.tsx | 12 ++++--- .../AgentButton/AgentNotRunningButton.tsx | 34 +++++++++++-------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx index e0fc24a33..ba1f8180f 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx @@ -4,7 +4,7 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; -import { useStakingContractDetails } from '@/hooks/useStakingContractDetails'; +import { useActiveStakingContractInfo } from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { assertRequired } from '@/types/Util'; @@ -21,20 +21,22 @@ export const AgentButton = () => { const { selectedService } = useServices(); const { activeStakingProgramId } = useStakingProgram(); + const serviceConfigId = selectedService?.service_config_id; + const { service, deploymentStatus: serviceStatus, isLoaded, - } = useService({ serviceConfigId: selectedService?.service_config_id }); + } = useService({ serviceConfigId }); assertRequired( + // TODO: review whether this causes agent button to not render activeStakingProgramId, 'Active staking program ID is required', ); - const { isEligibleForStaking, isAgentEvicted } = useStakingContractDetails( - activeStakingProgramId, - ); + const { isEligibleForStaking, isAgentEvicted } = + useActiveStakingContractInfo(); return useMemo(() => { if (!isLoaded) { diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index 08c5ce38e..fbe8aaf3c 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -2,7 +2,9 @@ import { Button, ButtonProps } from 'antd'; import { useCallback, useMemo } from 'react'; import { MiddlewareChain, MiddlewareDeploymentStatus } from '@/client'; +import { MechType } from '@/config/mechs'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; +import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; import { LOW_MASTER_SAFE_BALANCE } from '@/constants/thresholds'; import { TokenSymbol } from '@/enums/Token'; import { @@ -12,11 +14,9 @@ import { import { useElectronApi } from '@/hooks/useElectronApi'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; -import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useActiveStakingContractInfo, useStakingContractContext, - useStakingContractDetails, } from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { useStore } from '@/hooks/useStore'; @@ -26,7 +26,7 @@ import { WalletService } from '@/service/Wallet'; import { delayInSeconds } from '@/utils/delay'; /** Button used to start / deploy the agent */ -export const AgentNotRunningButton = (serviceConfigId: string) => { +export const AgentNotRunningButton = () => { const { masterWallets: wallets } = useMasterWalletContext(); const { selectedService, @@ -38,7 +38,6 @@ export const AgentNotRunningButton = (serviceConfigId: string) => { serviceConfigId: isLoaded && selectedService ? selectedService?.service_config_id : '', }); - const { serviceTemplate } = useServiceTemplates(); const { showNotification } = useElectronApi(); const { setIsPaused: setIsBalancePollingPaused, @@ -46,8 +45,9 @@ export const AgentNotRunningButton = (serviceConfigId: string) => { totalEthBalance, updateBalances, } = useBalanceContext(); - const { serviceSafeBalances, isLowBalance } = - useServiceBalances(serviceConfigId); + const { serviceSafeBalances, isLowBalance } = useServiceBalances( + selectedService?.service_config_id, + ); const { storeState } = useStore(); const { isAllStakingContractDetailsRecordLoaded, @@ -57,12 +57,11 @@ export const AgentNotRunningButton = (serviceConfigId: string) => { const { activeStakingProgramId } = useStakingProgram(); const { isEligibleForStaking, isAgentEvicted, isServiceStaked } = useActiveStakingContractInfo(); - const { hasEnoughServiceSlots } = useStakingContractDetails( - activeStakingProgramId, - ); + const { hasEnoughServiceSlots } = useActiveStakingContractInfo(); const requiredStakedOlas = service && + activeStakingProgramId && STAKING_PROGRAMS[service.home_chain_id][activeStakingProgramId] ?.stakingRequirements[TokenSymbol.OLAS]; @@ -102,15 +101,22 @@ export const AgentNotRunningButton = (serviceConfigId: string) => { }, [service]); const deployAndStartService = useCallback(async () => { - await ServicesService.createService({ + if (!activeStakingProgramId) return; + + const middlewareServiceResponse = await ServicesService.createService({ stakingProgramId: activeStakingProgramId, - serviceTemplate, + serviceTemplate: SERVICE_TEMPLATES[0], // TODO: support multi-agent, during optimus week deploy: true, - useMechMarketplace: false, + useMechMarketplace: + STAKING_PROGRAMS[+SERVICE_TEMPLATES[0].home_chain_id][ // TODO: support multi-agent, during optimus week + activeStakingProgramId + ].mechType === MechType.Marketplace, }); - await ServicesService.startService(serviceConfigId); - }, [activeStakingProgramId, serviceTemplate, serviceConfigId]); + await ServicesService.startService( + middlewareServiceResponse.service_config_id, + ); + }, [activeStakingProgramId]); const updateStatesSequentially = useCallback(async () => { await updateServicesState?.(); From 2157686a5347f5f6cfe491d4f9955a5b5a6a249e Mon Sep 17 00:00:00 2001 From: Atatakai Date: Thu, 21 Nov 2024 18:46:48 +0400 Subject: [PATCH 326/463] refactor: finalize useNeedsFunds hook, update MainNeedsFunds --- .../MainPage/sections/NeedsFundsSection.tsx | 11 +- frontend/hooks/useNeedsFunds.ts | 141 ++++++++++-------- 2 files changed, 84 insertions(+), 68 deletions(-) diff --git a/frontend/components/MainPage/sections/NeedsFundsSection.tsx b/frontend/components/MainPage/sections/NeedsFundsSection.tsx index b153611c9..cb5abf400 100644 --- a/frontend/components/MainPage/sections/NeedsFundsSection.tsx +++ b/frontend/components/MainPage/sections/NeedsFundsSection.tsx @@ -6,6 +6,7 @@ import { CustomAlert } from '@/components/Alert'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; +import { useServices } from '@/hooks/useServices'; import { CardSection } from '../../styled/CardSection'; @@ -28,6 +29,9 @@ export const MainNeedsFunds = () => { needsInitialFunding, } = useNeedsFunds(); + const { selectedAgentConfig } = useServices(); + const { homeChainId } = selectedAgentConfig; + const electronApi = useElectronApi(); const message: ReactNode = useMemo( @@ -37,14 +41,14 @@ export const MainNeedsFunds = () => { {!hasEnoughOlasForInitialFunding && (
- {`${UNICODE_SYMBOLS.OLAS}${serviceFundRequirements.olas} OLAS `} + {`${UNICODE_SYMBOLS.OLAS}${serviceFundRequirements[homeChainId].olas} OLAS `} for staking
)} {!hasEnoughEthForInitialFunding && (
- {`$${serviceFundRequirements.eth} XDAI `} + {`$${serviceFundRequirements[homeChainId].eth} XDAI `} for trading
@@ -56,9 +60,10 @@ export const MainNeedsFunds = () => {
), [ + hasEnoughOlasForInitialFunding, serviceFundRequirements, + homeChainId, hasEnoughEthForInitialFunding, - hasEnoughOlasForInitialFunding, ], ); diff --git a/frontend/hooks/useNeedsFunds.ts b/frontend/hooks/useNeedsFunds.ts index fac61fae0..46ef87a2a 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -2,24 +2,20 @@ import { formatEther, formatUnits } from 'ethers/lib/utils'; import { useMemo } from 'react'; import { ServiceTemplate } from '@/client'; -import { CHAIN_CONFIG } from '@/config/chains'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; +import { getNativeTokenSymbol } from '@/config/tokens'; import { getServiceTemplate } from '@/constants/serviceTemplates'; +import { TokenSymbol } from '@/enums/Token'; -import { useBalanceContext } from './useBalanceContext'; +import { useBalanceContext, useMasterBalances } from './useBalanceContext'; import { useService } from './useService'; import { useStore } from './useStore'; -import { TokenSymbol } from '@/enums/Token'; -import { getNativeTokenSymbol, NATIVE_TOKEN_CONFIG } from '@/config/tokens'; -import { useMasterWalletContext } from './useWallet'; -export const useNeedsFunds = (serviceConfigId: string) => { +export const useNeedsFunds = (serviceConfigId?: string) => { const { storeState } = useStore(); const { service } = useService({ serviceConfigId }); - const { masterSafes } = useMasterWalletContext(); - const { isLoaded: isBalanceLoaded, walletBalances } = - useBalanceContext(); - + const { isLoaded: isBalanceLoaded, walletBalances } = useBalanceContext(); + const { masterSafeBalances } = useMasterBalances(); const isInitialFunded = storeState?.isInitialFunded; @@ -28,35 +24,38 @@ export const useNeedsFunds = (serviceConfigId: string) => { [service], ); - const serviceFundRequirements = useMemo< { + const serviceFundRequirements = useMemo<{ [chainId: number]: { - [tokenSymbol: string]: number; - } + [tokenSymbol: string]: number; + }; }>(() => { if (!serviceTemplate) return {}; const results: { [chainId: number]: { - [tokenSymbol: string]: number; - } + [tokenSymbol: string]: number; + }; } = {}; Object.entries(serviceTemplate.configurations).forEach( ([chainId, config]) => { - const serviceTemplateDefault = serviceTemplate.configurations[+chainId].staking_program_id - const serviceCurrent = service?.chain_configs[+chainId]?.chain_data?.user_params?.staking_program_id - - if (!serviceCurrent && !serviceTemplateDefault) return; - + const templateStakingProgramId = + serviceTemplate.configurations[+chainId].staking_program_id; + const serviceStakingProgramId = + service?.chain_configs[+chainId]?.chain_data?.user_params + ?.staking_program_id; + const stakingProgramId = + serviceStakingProgramId ?? templateStakingProgramId; + + if (!stakingProgramId) return; if (!service?.chain_configs[+chainId]) return; + const gasEstimate = config.monthly_gas_estimate; const monthlyGasEstimate = Number(formatUnits(`${gasEstimate}`, 18)); const minimumStakedAmountRequired = - STAKING_PROGRAMS[+chainId][ - service?.chain_configs[+chainId]?.chain_data?.user_params - ?.staking_program_id ?? - serviceTemplate.configurations[+chainId].staking_program_id - ].stakingRequirements.OLAS; + STAKING_PROGRAMS[+chainId]?.[stakingProgramId]?.stakingRequirements?.[ + TokenSymbol.OLAS + ] || 0; const nativeTokenSymbol = getNativeTokenSymbol(+chainId); @@ -69,48 +68,60 @@ export const useNeedsFunds = (serviceConfigId: string) => { ); return results; - }, [serviceTemplate]); - - const hasEnoughEthForInitialFunding = useMemo( - () => { - if (!serviceFundRequirements) return ; - if (!walletBalances) return ; - - const nativeBalancesByChain = walletBalances.reduce<{[chainId: number]: number}>((acc, {symbol, balance, chainId}) => { - if (getNativeTokenSymbol(chainId) !== symbol) return acc; - - if (!acc[chainId]) acc[chainId] = 0; - acc[chainId] += balance; - - return acc; - }, {}); - - const chainIds = Object.keys(serviceFundRequirements).map(Number); - - return chainIds.every(chainId => { - const nativeTokenSymbol = getNativeTokenSymbol(chainId); - const nativeTokenBalance = nativeBalancesByChain[chainId] || 0; - const nativeTokenRequired = serviceFundRequirements[chainId]?.[nativeTokenSymbol] || 0; - - return nativeTokenBalance >= nativeTokenRequired; - }); - - }, - [], - ); + }, [service?.chain_configs, serviceTemplate]); + + const hasEnoughEthForInitialFunding = useMemo(() => { + if (!serviceFundRequirements) return; + if (!walletBalances) return; + + const nativeBalancesByChain = walletBalances.reduce<{ + [chainId: number]: number; + }>((acc, { symbol, balance, chainId }) => { + if (getNativeTokenSymbol(chainId) !== symbol) return acc; + + if (!acc[chainId]) acc[chainId] = 0; + acc[chainId] += balance; + + return acc; + }, {}); + + const chainIds = Object.keys(serviceFundRequirements).map(Number); + + return chainIds.every((chainId) => { + const nativeTokenSymbol = getNativeTokenSymbol(chainId); + const nativeTokenBalance = nativeBalancesByChain[chainId] || 0; + const nativeTokenRequired = + serviceFundRequirements[chainId]?.[nativeTokenSymbol] || 0; + + return nativeTokenBalance >= nativeTokenRequired; + }); + }, [serviceFundRequirements, walletBalances]); - // TODO: refactor this to use the new balance context const hasEnoughOlasForInitialFunding = useMemo(() => { - const olasInSafe = safeBalance?.OLAS || 0; - const olasStakedBySafe = totalStakedOlasBalance || 0; - const olasRequiredToFundService = serviceFundRequirements.olas || 0; - const olasInSafeAndStaked = olasInSafe + olasStakedBySafe; - return olasInSafeAndStaked >= olasRequiredToFundService; - }, [ - safeBalance?.OLAS, - totalStakedOlasBalance, - serviceFundRequirements?.olas, - ]); + if (!serviceFundRequirements) return; + if (!masterSafeBalances) return; + + const olasBalancesByChain = masterSafeBalances.reduce<{ + [chainId: number]: number; + }>((acc, { symbol, balance, chainId }) => { + if (TokenSymbol.OLAS !== symbol) return acc; + + if (!acc[chainId]) acc[chainId] = 0; + acc[chainId] += balance; + + return acc; + }, {}); + + const chainIds = Object.keys(serviceFundRequirements).map(Number); + + return chainIds.every((chainId) => { + const olasBalance = olasBalancesByChain[chainId] || 0; + const olasRequired = + serviceFundRequirements[chainId]?.[TokenSymbol.OLAS] || 0; + + return olasBalance >= olasRequired; + }); + }, [masterSafeBalances, serviceFundRequirements]); const needsInitialFunding: boolean = useMemo(() => { if (isInitialFunded) return false; From 038f35efb1b5106235e7b93f6a8891b2ae702aa4 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 15:17:58 +0000 Subject: [PATCH 327/463] feat: rename ServiceStakingState to StakingState for consistency and clarity --- frontend/hooks/useStakingContractDetails.ts | 8 +++----- frontend/types/Autonolas.ts | 8 ++++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/frontend/hooks/useStakingContractDetails.ts b/frontend/hooks/useStakingContractDetails.ts index 41a8b34ac..76bff9bae 100644 --- a/frontend/hooks/useStakingContractDetails.ts +++ b/frontend/hooks/useStakingContractDetails.ts @@ -3,7 +3,7 @@ import { useContext } from 'react'; import { StakingContractDetailsContext } from '@/context/StakingContractDetailsProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { ServiceStakingState } from '@/types/Autonolas'; +import { StakingState } from '@/types/Autonolas'; import { useServices } from './useServices'; @@ -65,12 +65,10 @@ export const useActiveStakingContractInfo = () => { maxNumServices, } = activeStakingContractDetails ?? {}; - const isAgentEvicted = - serviceStakingState === ServiceStakingState.EvictedOrUnstaked; + const isAgentEvicted = serviceStakingState === StakingState.Evicted; const isServiceStaked = - !!serviceStakingStartTime && - serviceStakingState === ServiceStakingState.Staked; + !!serviceStakingStartTime && serviceStakingState === StakingState.Staked; const isRewardsAvailable = availableRewards ?? 0 > 0; diff --git a/frontend/types/Autonolas.ts b/frontend/types/Autonolas.ts index 2c0e3fefe..1194ece9a 100644 --- a/frontend/types/Autonolas.ts +++ b/frontend/types/Autonolas.ts @@ -14,10 +14,10 @@ export const StakingRewardsInfoSchema = z.object({ export type StakingRewardsInfo = z.infer; -export enum ServiceStakingState { +export enum StakingState { NotStaked = 0, Staked = 1, - EvictedOrUnstaked = 2, + Evicted = 2, } export type StakingContractDetails = { @@ -29,8 +29,8 @@ export type StakingContractDetails = { minimumStakingDuration: number; /** time when service was staked (in seconds) - 0 = never staked */ serviceStakingStartTime: number; - /** 0: not staked, 1: staked, 2: unstaked - current state of the service */ - serviceStakingState: ServiceStakingState; + /** 0: not staked, 1: staked, 2: evicted */ + serviceStakingState: StakingState; /** OLAS cost of staking */ minStakingDeposit: number; /** estimated annual percentage yield */ From e4fd9429ed96f98f88ff36add2dacbb62813d8d2 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 21 Nov 2024 17:22:53 +0100 Subject: [PATCH 328/463] chore: bump autonomy --- poetry.lock | 2308 ++++++++++++++++++++++++++---------------------- pyproject.toml | 10 +- 2 files changed, 1234 insertions(+), 1084 deletions(-) diff --git a/poetry.lock b/poetry.lock index fa2061054..e493fe912 100644 --- a/poetry.lock +++ b/poetry.lock @@ -134,13 +134,13 @@ files = [ [[package]] name = "anyio" -version = "4.4.0" +version = "4.6.2.post1" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"}, - {file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"}, + {file = "anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d"}, + {file = "anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c"}, ] [package.dependencies] @@ -150,9 +150,9 @@ sniffio = ">=1.1" typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""} [package.extras] -doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] -trio = ["trio (>=0.23)"] +doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21.0b1)"] +trio = ["trio (>=0.26.1)"] [[package]] name = "asn1crypto" @@ -222,38 +222,36 @@ tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", " [[package]] name = "bcrypt" -version = "4.2.0" +version = "4.2.1" description = "Modern password hashing for your software and your servers" optional = false python-versions = ">=3.7" files = [ - {file = "bcrypt-4.2.0-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:096a15d26ed6ce37a14c1ac1e48119660f21b24cba457f160a4b830f3fe6b5cb"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c02d944ca89d9b1922ceb8a46460dd17df1ba37ab66feac4870f6862a1533c00"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d84cf6d877918620b687b8fd1bf7781d11e8a0998f576c7aa939776b512b98d"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1bb429fedbe0249465cdd85a58e8376f31bb315e484f16e68ca4c786dcc04291"}, - {file = "bcrypt-4.2.0-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:655ea221910bcac76ea08aaa76df427ef8625f92e55a8ee44fbf7753dbabb328"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:1ee38e858bf5d0287c39b7a1fc59eec64bbf880c7d504d3a06a96c16e14058e7"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:0da52759f7f30e83f1e30a888d9163a81353ef224d82dc58eb5bb52efcabc399"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3698393a1b1f1fd5714524193849d0c6d524d33523acca37cd28f02899285060"}, - {file = "bcrypt-4.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:762a2c5fb35f89606a9fde5e51392dad0cd1ab7ae64149a8b935fe8d79dd5ed7"}, - {file = "bcrypt-4.2.0-cp37-abi3-win32.whl", hash = "sha256:5a1e8aa9b28ae28020a3ac4b053117fb51c57a010b9f969603ed885f23841458"}, - {file = "bcrypt-4.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:8f6ede91359e5df88d1f5c1ef47428a4420136f3ce97763e31b86dd8280fbdf5"}, - {file = "bcrypt-4.2.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:c52aac18ea1f4a4f65963ea4f9530c306b56ccd0c6f8c8da0c06976e34a6e841"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3bbbfb2734f0e4f37c5136130405332640a1e46e6b23e000eeff2ba8d005da68"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3413bd60460f76097ee2e0a493ccebe4a7601918219c02f503984f0a7ee0aebe"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:8d7bb9c42801035e61c109c345a28ed7e84426ae4865511eb82e913df18f58c2"}, - {file = "bcrypt-4.2.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3d3a6d28cb2305b43feac298774b997e372e56c7c7afd90a12b3dc49b189151c"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:9c1c4ad86351339c5f320ca372dfba6cb6beb25e8efc659bedd918d921956bae"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:27fe0f57bb5573104b5a6de5e4153c60814c711b29364c10a75a54bb6d7ff48d"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:8ac68872c82f1add6a20bd489870c71b00ebacd2e9134a8aa3f98a0052ab4b0e"}, - {file = "bcrypt-4.2.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cb2a8ec2bc07d3553ccebf0746bbf3d19426d1c6d1adbd4fa48925f66af7b9e8"}, - {file = "bcrypt-4.2.0-cp39-abi3-win32.whl", hash = "sha256:77800b7147c9dc905db1cba26abe31e504d8247ac73580b4aa179f98e6608f34"}, - {file = "bcrypt-4.2.0-cp39-abi3-win_amd64.whl", hash = "sha256:61ed14326ee023917ecd093ee6ef422a72f3aec6f07e21ea5f10622b735538a9"}, - {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:39e1d30c7233cfc54f5c3f2c825156fe044efdd3e0b9d309512cc514a263ec2a"}, - {file = "bcrypt-4.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:f4f4acf526fcd1c34e7ce851147deedd4e26e6402369304220250598b26448db"}, - {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:1ff39b78a52cf03fdf902635e4c81e544714861ba3f0efc56558979dd4f09170"}, - {file = "bcrypt-4.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:373db9abe198e8e2c70d12b479464e0d5092cc122b20ec504097b5f2297ed184"}, - {file = "bcrypt-4.2.0.tar.gz", hash = "sha256:cf69eaf5185fd58f268f805b505ce31f9b9fc2d64b376642164e9244540c1221"}, + {file = "bcrypt-4.2.1-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:1340411a0894b7d3ef562fb233e4b6ed58add185228650942bdc885362f32c17"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ee315739bc8387aa36ff127afc99120ee452924e0df517a8f3e4c0187a0f5f"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dbd0747208912b1e4ce730c6725cb56c07ac734b3629b60d4398f082ea718ad"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:aaa2e285be097050dba798d537b6efd9b698aa88eef52ec98d23dcd6d7cf6fea"}, + {file = "bcrypt-4.2.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:76d3e352b32f4eeb34703370e370997065d28a561e4a18afe4fef07249cb4396"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:b7703ede632dc945ed1172d6f24e9f30f27b1b1a067f32f68bf169c5f08d0425"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:89df2aea2c43be1e1fa066df5f86c8ce822ab70a30e4c210968669565c0f4685"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:04e56e3fe8308a88b77e0afd20bec516f74aecf391cdd6e374f15cbed32783d6"}, + {file = "bcrypt-4.2.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:cfdf3d7530c790432046c40cda41dfee8c83e29482e6a604f8930b9930e94139"}, + {file = "bcrypt-4.2.1-cp37-abi3-win32.whl", hash = "sha256:adadd36274510a01f33e6dc08f5824b97c9580583bd4487c564fc4617b328005"}, + {file = "bcrypt-4.2.1-cp37-abi3-win_amd64.whl", hash = "sha256:8c458cd103e6c5d1d85cf600e546a639f234964d0228909d8f8dbeebff82d526"}, + {file = "bcrypt-4.2.1-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:8ad2f4528cbf0febe80e5a3a57d7a74e6635e41af1ea5675282a33d769fba413"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:909faa1027900f2252a9ca5dfebd25fc0ef1417943824783d1c8418dd7d6df4a"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cde78d385d5e93ece5479a0a87f73cd6fa26b171c786a884f955e165032b262c"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:533e7f3bcf2f07caee7ad98124fab7499cb3333ba2274f7a36cf1daee7409d99"}, + {file = "bcrypt-4.2.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:687cf30e6681eeda39548a93ce9bfbb300e48b4d445a43db4298d2474d2a1e54"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:041fa0155c9004eb98a232d54da05c0b41d4b8e66b6fc3cb71b4b3f6144ba837"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f85b1ffa09240c89aa2e1ae9f3b1c687104f7b2b9d2098da4e923f1b7082d331"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c6f5fa3775966cca251848d4d5393ab016b3afed251163c1436fefdec3b02c84"}, + {file = "bcrypt-4.2.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:807261df60a8b1ccd13e6599c779014a362ae4e795f5c59747f60208daddd96d"}, + {file = "bcrypt-4.2.1-cp39-abi3-win32.whl", hash = "sha256:b588af02b89d9fad33e5f98f7838bf590d6d692df7153647724a7f20c186f6bf"}, + {file = "bcrypt-4.2.1-cp39-abi3-win_amd64.whl", hash = "sha256:e84e0e6f8e40a242b11bce56c313edc2be121cec3e0ec2d76fce01f6af33c07c"}, + {file = "bcrypt-4.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:76132c176a6d9953cdc83c296aeaed65e1a708485fd55abf163e0d9f8f16ce0e"}, + {file = "bcrypt-4.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e158009a54c4c8bc91d5e0da80920d048f918c61a581f0a63e4e93bb556d362f"}, + {file = "bcrypt-4.2.1.tar.gz", hash = "sha256:6765386e3ab87f569b276988742039baab087b2cdb01e809d74e74503c2faafe"}, ] [package.extras] @@ -273,133 +271,148 @@ files = [ [[package]] name = "bitarray" -version = "2.9.2" +version = "2.9.3" description = "efficient arrays of booleans -- C extension" optional = false python-versions = "*" files = [ - {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:917905de565d9576eb20f53c797c15ba88b9f4f19728acabec8d01eee1d3756a"}, - {file = "bitarray-2.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b35bfcb08b7693ab4bf9059111a6e9f14e07d57ac93cd967c420db58ab9b71e1"}, - {file = "bitarray-2.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ea1923d2e7880f9e1959e035da661767b5a2e16a45dfd57d6aa831e8b65ee1bf"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e0b63a565e8a311cc8348ff1262d5784df0f79d64031d546411afd5dd7ef67d"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cf0620da2b81946d28c0b16f3e3704d38e9837d85ee4f0652816e2609aaa4fed"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:79a9b8b05f2876c7195a2b698c47528e86a73c61ea203394ff8e7a4434bda5c8"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:345c76b349ff145549652436235c5532e5bfe9db690db6f0a6ad301c62b9ef21"}, - {file = "bitarray-2.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e2936f090bf3f4d1771f44f9077ebccdbc0415d2b598d51a969afcb519df505"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f9346e98fc2abcef90b942973087e2462af6d3e3710e82938078d3493f7fef52"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e6ec283d4741befb86e8c3ea2e9ac1d17416c956d392107e45263e736954b1f7"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:962892646599529917ef26266091e4cb3077c88b93c3833a909d68dcc971c4e3"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:e8da5355d7d75a52df5b84750989e34e39919ec7e59fafc4c104cc1607ab2d31"}, - {file = "bitarray-2.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:603e7d640e54ad764d2b4da6b61e126259af84f253a20f512dd10689566e5478"}, - {file = "bitarray-2.9.2-cp310-cp310-win32.whl", hash = "sha256:f00079f8e69d75c2a417de7961a77612bb77ef46c09bc74607d86de4740771ef"}, - {file = "bitarray-2.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:1bb33673e7f7190a65f0a940c1ef63266abdb391f4a3e544a47542d40a81f536"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe71fd4b76380c2772f96f1e53a524da7063645d647a4fcd3b651bdd80ca0f2e"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d527172919cdea1e13994a66d9708a80c3d33dedcf2f0548e4925e600fef3a3a"}, - {file = "bitarray-2.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:052c5073bdcaa9dd10628d99d37a2f33ec09364b86dd1f6281e2d9f8d3db3060"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e064caa55a6ed493aca1eda06f8b3f689778bc780a75e6ad7724642ba5dc62f7"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:508069a04f658210fdeee85a7a0ca84db4bcc110cbb1d21f692caa13210f24a7"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4da73ebd537d75fa7bccfc2228fcaedea0803f21dd9d0bf0d3b67fef3c4af294"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cb378eaa65cd43098f11ff5d27e48ee3b956d2c00d2d6b5bfc2a09fe183be47"}, - {file = "bitarray-2.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d14c790b91f6cbcd9b718f88ed737c78939980c69ac8c7f03dd7e60040c12951"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7eea9318293bc0ea6447e9ebfba600a62f3428bea7e9c6d42170ae4f481dbab3"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b76ffec27c7450b8a334f967366a9ebadaea66ee43f5b530c12861b1a991f503"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:76b76a07d4ee611405045c6950a1e24c4362b6b44808d4ad6eea75e0dbc59af4"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:c7d16beeaaab15b075990cd26963d6b5b22e8c5becd131781514a00b8bdd04bd"}, - {file = "bitarray-2.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60df43e868a615c7e15117a1e1c2e5e11f48f6457280eba6ddf8fbefbec7da99"}, - {file = "bitarray-2.9.2-cp311-cp311-win32.whl", hash = "sha256:e788608ed7767b7b3bbde6d49058bccdf94df0de9ca75d13aa99020cc7e68095"}, - {file = "bitarray-2.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:a23397da092ef0a8cfe729571da64c2fc30ac18243caa82ac7c4f965087506ff"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:90e3a281ffe3897991091b7c46fca38c2675bfd4399ffe79dfeded6c52715436"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bed637b674db5e6c8a97a4a321e3e4d73e72d50b5c6b29950008a93069cc64cd"}, - {file = "bitarray-2.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e49066d251dbbe4e6e3a5c3937d85b589e40e2669ad0eef41a00f82ec17d844b"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c4344e96642e2211fb3a50558feff682c31563a4c64529a931769d40832ca79"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aeb60962ec4813c539a59fbd4f383509c7222b62c3fb1faa76b54943a613e33a"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed0f7982f10581bb16553719e5e8f933e003f5b22f7d25a68bdb30fac630a6ff"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c71d1cabdeee0cdda4669168618f0e46b7dace207b29da7b63aaa1adc2b54081"}, - {file = "bitarray-2.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0ef2d0a6f1502d38d911d25609b44c6cc27bee0a4363dd295df78b075041b60"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6f71d92f533770fb027388b35b6e11988ab89242b883f48a6fe7202d238c61f8"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ba0734aa300757c924f3faf8148e1b8c247176a0ac8e16aefdf9c1eb19e868f7"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d91406f413ccbf4af6ab5ae7bc78f772a95609f9ddd14123db36ef8c37116d95"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:87abb7f80c0a042f3fe8e5264da1a2756267450bb602110d5327b8eaff7682e7"}, - {file = "bitarray-2.9.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b558ce85579b51a2e38703877d1e93b7728a7af664dd45a34e833534f0b755d"}, - {file = "bitarray-2.9.2-cp312-cp312-win32.whl", hash = "sha256:dac2399ee2889fbdd3472bfc2ede74c34cceb1ccf29a339964281a16eb1d3188"}, - {file = "bitarray-2.9.2-cp312-cp312-win_amd64.whl", hash = "sha256:48a30d718d1a6dfc22a49547450107abe8f4afdf2abdcbe76eb9ed88edc49498"}, - {file = "bitarray-2.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2c6be1b651fad8f3adb7a5aa12c65b612cd9b89530969af941844ae680f7d981"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5b399ae6ab975257ec359f03b48fc00b1c1cd109471e41903548469b8feae5c"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0b3543c8a1cb286ad105f11c25d8d0f712f41c5c55f90be39f0e5a1376c7d0b0"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:03adaacb79e2fb8f483ab3a67665eec53bb3fd0cd5dbd7358741aef124688db3"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ae5b0657380d2581e13e46864d147a52c1e2bbac9f59b59c576e42fa7d10cf0"}, - {file = "bitarray-2.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c1f4bf6ea8eb9d7f30808c2e9894237a96650adfecbf5f3643862dc5982f89e"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a8873089be2aa15494c0f81af1209f6e1237d762c5065bc4766c1b84321e1b50"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:677e67f50e2559efc677a4366707070933ad5418b8347a603a49a070890b19bc"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:a620d8ce4ea2f1c73c6b6b1399e14cb68c6915e2be3fad5808c2998ed55b4acf"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:64115ccabbdbe279c24c367b629c6b1d3da9ed36c7420129e27c338a3971bfee"}, - {file = "bitarray-2.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:5d6fb422772e75385b76ad1c52f45a68bd4efafd8be8d0061c11877be74c4d43"}, - {file = "bitarray-2.9.2-cp36-cp36m-win32.whl", hash = "sha256:852e202875dd6dfd6139ce7ec4e98dac2b17d8d25934dc99900831e81c3adaef"}, - {file = "bitarray-2.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:7dfefdcb0dc6a3ba9936063cec65a74595571b375beabe18742b3d91d087eefd"}, - {file = "bitarray-2.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b306c4cf66912511422060f7f5e1149c8bdb404f8e00e600561b0749fdd45659"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a09c4f81635408e3387348f415521d4b94198c562c23330f560596a6aaa26eaf"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5361413fd2ecfdf44dc8f065177dc6aba97fa80a91b815586cb388763acf7f8d"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e8a9475d415ef1eaae7942df6f780fa4dcd48fce32825eda591a17abba869299"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9b87baa7bfff9a5878fcc1bffe49ecde6e647a72a64b39a69cd8a2992a43a34"}, - {file = "bitarray-2.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb6b86cfdfc503e92cb71c68766a24565359136961642504a7cc9faf936d9c88"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cd56b8ae87ebc71bcacbd73615098e8a8de952ecbb5785b6b4e2b07da8a06e1f"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3fa909cfd675004aed8b4cc9df352415933656e0155a6209d878b7cb615c787e"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b069ca9bf728e0c5c5b60e00a89df9af34cc170c695c3bfa3b372d8f40288efb"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:6067f2f07a7121749858c7daa93c8774325c91590b3e81a299621e347740c2ae"}, - {file = "bitarray-2.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:321841cdad1dd0f58fe62e80e9c9c7531f8ebf8be93f047401e930dc47425b1e"}, - {file = "bitarray-2.9.2-cp37-cp37m-win32.whl", hash = "sha256:54e16e32e60973bb83c315de9975bc1bcfc9bd50bb13001c31da159bc49b0ca1"}, - {file = "bitarray-2.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:f4dcadb7b8034aa3491ee8f5a69b3d9ba9d7d1e55c3cc1fc45be313e708277f8"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c8919fdbd3bb596b104388b56ae4b266eb28da1f2f7dff2e1f9334a21840fe96"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb7a9d8a2e400a1026de341ad48e21670a6261a75b06df162c5c39b0d0e7c8f4"}, - {file = "bitarray-2.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6ec84668dd7b937874a2b2c293cd14ba84f37be0d196dead852e0ada9815d807"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2de9a31c34e543ae089fd2a5ced01292f725190e379921384f695e2d7184bd3"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9521f49ae121a17c0a41e5112249e6fa7f6a571245b1118de81fb86e7c1bc1ce"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6cc6545d6d76542aee3d18c1c9485fb7b9812b8df4ebe52c4535ec42081b48f"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:856bbe1616425f71c0df5ef2e8755e878d9504d5a531acba58ab4273c52c117a"}, - {file = "bitarray-2.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d4bba8042ea6ab331ade91bc435d81ad72fddb098e49108610b0ce7780c14e68"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a035da89c959d98afc813e3c62f052690d67cfd55a36592f25d734b70de7d4b0"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d70b1579da7fb71be5a841a1f965d19aca0ef27f629cfc07d06b09aafd0a333"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:405b83bed28efaae6d86b6ab287c75712ead0adbfab2a1075a1b7ab47dad4d62"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:7eb8be687c50da0b397d5e0ab7ca200b5ebb639e79a9f5e285851d1944c94be9"}, - {file = "bitarray-2.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:eceb551dfeaf19c609003a69a0cf8264b0efd7abc3791a11dfabf4788daf0d19"}, - {file = "bitarray-2.9.2-cp38-cp38-win32.whl", hash = "sha256:bb198c6ed1edbcdaf3d1fa3c9c9d1cdb7e179a5134ef5ee660b53cdec43b34e7"}, - {file = "bitarray-2.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:648d2f2685590b0103c67a937c2fb9e09bcc8dfb166f0c7c77bd341902a6f5b3"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ea816dc8f8e65841a8bbdd30e921edffeeb6f76efe6a1eb0da147b60d539d1cf"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4d0e32530f941c41eddfc77600ec89b65184cb909c549336463a738fab3ed285"}, - {file = "bitarray-2.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4a22266fb416a3b6c258bf7f83c9fe531ba0b755a56986a81ad69dc0f3bcc070"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc6d3e80dd8239850f2604833ff3168b28909c8a9357abfed95632cccd17e3e7"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f135e804986b12bf14f2cd1eb86674c47dea86c4c5f0fa13c88978876b97ebe6"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87580c7f7d14f7ec401eda7adac1e2a25e95153e9c339872c8ae61b3208819a1"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64b433e26993127732ac7b66a7821b2537c3044355798de7c5fcb0af34b8296f"}, - {file = "bitarray-2.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e497c535f2a9b68c69d36631bf2dba243e05eb343b00b9c7bbdc8c601c6802d"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e40b3cb9fa1edb4e0175d7c06345c49c7925fe93e39ef55ecb0bc40c906b0c09"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f2f8692f95c9e377eb19ca519d30d1f884b02feb7e115f798de47570a359e43f"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f0b84fc50b6dbeced4fa390688c07c10a73222810fb0e08392bd1a1b8259de36"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d656ad38c942e38a470ddbce26b5020e08e1a7ea86b8fd413bb9024b5189993a"}, - {file = "bitarray-2.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6ab0f1dbfe5070db98771a56aa14797595acd45a1af9eadfb193851a270e7996"}, - {file = "bitarray-2.9.2-cp39-cp39-win32.whl", hash = "sha256:0a99b23ac845a9ea3157782c97465e6ae026fe0c7c4c1ed1d88f759fd6ea52d9"}, - {file = "bitarray-2.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:9bbcfc7c279e8d74b076e514e669b683f77b4a2a328585b3f16d4c5259c91222"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:43847799461d8ba71deb4d97b47250c2c2fb66d82cd3cb8b4caf52bb97c03034"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f44381b0a4bdf64416082f4f0e7140377ae962c0ced6f983c6d7bbfc034040"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a484061616fb4b158b80789bd3cb511f399d2116525a8b29b6334c68abc2310f"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ff9e38356cc803e06134cf8ae9758e836ccd1b793135ef3db53c7c5d71e93bc"}, - {file = "bitarray-2.9.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b44105792fbdcfbda3e26ee88786790fda409da4c71f6c2b73888108cf8f062f"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7e913098de169c7fc890638ce5e171387363eb812579e637c44261460ac00aa2"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6fe315355cdfe3ed22ef355b8bdc81a805ca4d0949d921576560e5b227a1112"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f708e91fdbe443f3bec2df394ed42328fb9b0446dff5cb4199023ac6499e09fd"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b7b09489b71f9f1f64c0fa0977e250ec24500767dab7383ba9912495849cadf"}, - {file = "bitarray-2.9.2-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:128cc3488176145b9b137fdcf54c1c201809bbb8dd30b260ee40afe915843b43"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:21f21e7f56206be346bdbda2a6bdb2165a5e6a11821f88fd4911c5a6bbbdc7e2"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f4dd3af86dd8a617eb6464622fb64ca86e61ce99b59b5c35d8cd33f9c30603d"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6465de861aff7a2559f226b37982007417eab8c3557543879987f58b453519bd"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbaf2bb71d6027152d603f1d5f31e0dfd5e50173d06f877bec484e5396d4594b"}, - {file = "bitarray-2.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:2f32948c86e0d230a296686db28191b67ed229756f84728847daa0c7ab7406e3"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:be94e5a685e60f9d24532af8fe5c268002e9016fa80272a94727f435de3d1003"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5cc9381fd54f3c23ae1039f977bfd6d041a5c3c1518104f616643c3a5a73b15"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd926e8ae4d1ed1ac4a8f37212a62886292f692bc1739fde98013bf210c2d175"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:461a3dafb9d5fda0bb3385dc507d78b1984b49da3fe4c6d56c869a54373b7008"}, - {file = "bitarray-2.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:393cb27fd859af5fd9c16eb26b1c59b17b390ff66b3ae5d0dd258270191baf13"}, - {file = "bitarray-2.9.2.tar.gz", hash = "sha256:a8f286a51a32323715d77755ed959f94bef13972e9a2fe71b609e40e6d27957e"}, + {file = "bitarray-2.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2cf5f5400636c7dda797fd681795ce63932458620fe8c40955890380acba9f62"}, + {file = "bitarray-2.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3487b4718ffa5942fab777835ee36085f8dda7ec4bd0b28433efb117f84852b6"}, + {file = "bitarray-2.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:10f44b1e4994035408bea54d7bf0aec79744cad709706bedf28091a48bb7f1a4"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb5c16f97c65add6535748a9c98c70e7ca79759c38a2eb990127fef72f76111a"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13dbfc42971ba84e9c4ba070f720df6570285a3f89187f07ef422efcb611c19f"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c28076acfbe7f9a5494d7ae98094a6e209c390c340938845f294818ebf5e4d3"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7cdd21835936d9a66477836ca23b2cb63295142cb9d9158883e2c0f1f8f6bd"}, + {file = "bitarray-2.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f60887ab3a46e507fa6f8544d8d4b0748da48718591dfe3fe80c62bdea60f10"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f75e1abd4a37cba3002521d3f5e2b50ef4f4a74342207cad3f52468411d5d8ba"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dc63da9695383c048b83f5ab77eab35a55bbb2e77c7b6e762eba219929b45b84"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6fe5a57b859d9bc9c2fd27c78c4b7b83158faf984202de6fb44618caeebfff10"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1fe5a37bd9441a5ecc2f6e71b43df7176fa376a542ef97484310b8b46a45649a"}, + {file = "bitarray-2.9.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8a16e42c169ca818d6a15b5dd5acd5d2a26af0fa0588e1036e0e58d01f8387d4"}, + {file = "bitarray-2.9.3-cp310-cp310-win32.whl", hash = "sha256:5e6b5e7940af3474ffaa930cd1ce8215181cbe864d6b5ddb67a15d3c15e935cd"}, + {file = "bitarray-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:c63dbb99ef2ab1281871678624f9c9a5f1682b826e668ce559275ec488b3fa8b"}, + {file = "bitarray-2.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:49fb93b488d180f5c84b79fe687c585a84bf0295ff035d63e09ee24ce1da0558"}, + {file = "bitarray-2.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c2944fb83bbc2aa7f29a713bc4f8c1318e54fa0d06a72bedd350a3fb4a4b91d8"}, + {file = "bitarray-2.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3612d9d3788dc62f1922c917b1539f1cdf02cecc9faef8ae213a8b36093136ca"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90a9300cdb7c99b1e692bb790cba8acecee1a345a83e58e28c94a0d87c522237"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1211ed66acbbb221fd7554abf4206a384d79e6192d5cb95325c5c361bbb52a74"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67757279386accf93eba76b8f97b5acf1664a3e350cbea5f300f53490f8764fd"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64e19c6a99c32f460c2613f797f77aa37d8e298891d00ea5355158cce80e11ec"}, + {file = "bitarray-2.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72734bd3775f43c5a75385730abb9f84fee6c627eb14f579de4be478f1615c8c"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a92703471b5d3316c7481bc1852f620f42f7a1b62be27f39d13694827635786f"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d5d77c81300ca430d4b195ccfbb629d6858258f541b6e96c6b11ec1563cd2681"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3ba8a29c0d091c952ced1607ce715f5e0524899f24333a493807d00f5938463d"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:418171d035b191dbe5e86cd2bfb5c3e1ae7d947edc22857a897d1c7251674ae5"}, + {file = "bitarray-2.9.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e0bd272eba256183be2a17488f9cb096d2e6d3435ecf2e28c1e0857c6d20749"}, + {file = "bitarray-2.9.3-cp311-cp311-win32.whl", hash = "sha256:cc3fd2b0637a619cf13e122bbcf4729ae214d5f25623675597e67c25f9edfe61"}, + {file = "bitarray-2.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:e1fc2a81a585dbe5e367682156e6350d908a56e2ffd6ca651b0af01994db596f"}, + {file = "bitarray-2.9.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc47be026f76f1728af00dc7140cec8483fe2f0c476bbf2a59ef47865e00ff96"}, + {file = "bitarray-2.9.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:82b091742ff511cdb06f90af0d2c22e7af3dbff9b8212e2e0d88dfef6a8570b3"}, + {file = "bitarray-2.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d5edb4302a0e3a3d1d0eeb891de3c615d4cb7a446fb41c21eecdcfb29400a6f"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4786c5525069c19820549dd2f42d33632bc42959ad167138bd8ee5024b922b"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bfe2de2b4df61ccb9244871a0fdf1fff83be0c1bd7187048c3cf7f81c5fe631"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31e4f69538f95d2934587d957eea0d283162322dd1af29e57122b20b8cd60f92"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ca44908b2bc08d8995770018638d62626706864f9c599b7818225a12f3dbc2c"}, + {file = "bitarray-2.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:279f8de5d251ee521e365df29c927d9b5732f1ed4f373d2dbbd278fcbad94ff5"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49bb631b38431c09ecd534d56ef04264397d24d18c4ee6653c84e14ae09d92d"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:192bffc93ee9a5b6c833c98d1dcc81f5633ddd726b85e18341387d0c1d51f691"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c516cec28c6511df51d87033f40ec420324a2247469b0c989d344f4d27ea37d2"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:66241cb9a1c1db294f46cd440141e57e8242874e38f3f61877f72d92ae14768a"}, + {file = "bitarray-2.9.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ab1f0e7631110c89bea7b605c0c35832333eb9cc97e5de05d71c76d42a1858c9"}, + {file = "bitarray-2.9.3-cp312-cp312-win32.whl", hash = "sha256:42aa5bee6fe8ad3385eaf5c6585016bbc38a7b75efb52ce5c6f8e00e05237dfa"}, + {file = "bitarray-2.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:dc3fd647d845b94fac3652390866f921f914a17f3807a031c826f68dae3f43e3"}, + {file = "bitarray-2.9.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:fcfcc1989e3e021a282624017b7fb754210f5332e933b1c3ebc79643727b6551"}, + {file = "bitarray-2.9.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:71b1e229a706798a9e106ca7b03d4c63455deb40b18c92950ec073a05a8f8285"}, + {file = "bitarray-2.9.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4bb49556d3d505d24c942a4206ad4d0d40e89fa3016a7ea6edc994d5c08d4a8e"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4466aa1e533a59d5f7fd37219d154ec3f2ba73fce3d8a2e11080ec475bc15fb"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a9b75adc0fd0bf278bea89dc3d679d74e10d2df98d3d074b7f3d36f323138818"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:701582bbbeac372b1cd8a3c9daf6c2336dc2d22e14373a6271d788bc4f2b6edc"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ea1f119668bbdbd68008031491515e84441e505163918819994b28f295f762c"}, + {file = "bitarray-2.9.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9f400bc18a70bfdb073532c3054ecd78a0e64f96ff7b6140adde5b122580ec2b"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:aacff5656fb3e15cede7d02903da2634d376aa928d7a81ec8df19b0724d7972a"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8a2ae42a14cbf766d4478d7101da6359b0648dd813e60eb3486ac56ad2f5add3"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:616698edb547d10f0b960cb9f2e8629c55a420dd4c2b1ab46706f49a1815621d"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f277c50ba184929dfeed39b6cf9468e3446093521b0aeb52bd54a21ca08f5473"}, + {file = "bitarray-2.9.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:661237739b385c90d8837d5e96b06de093cc6e610236977e198f88f5a979686e"}, + {file = "bitarray-2.9.3-cp313-cp313-win32.whl", hash = "sha256:68acec6c19d798051f178a1197b76f891985f683f95a4b12811b68e58b080f5a"}, + {file = "bitarray-2.9.3-cp313-cp313-win_amd64.whl", hash = "sha256:3055720afdcfd7e8f630fa16db7bed7e55c9d0a1f4756195e3b250e203f3b436"}, + {file = "bitarray-2.9.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:72bf17d0e7d8a4f645655a07999d23e42472cbf2100b8dad7ce26586075241d7"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cfd332b5f1ad8c4dc3cc79ecef33c19b42d8d8e6a39fd5c9ecb5855be0b9723"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5b466ef1e48f25621c9d27e95deb5e33b8656827ed8aa530b972de73870bd1f"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:938cf26fdaf4d0adfac82d830c025523c5d36ddead0470b735286028231c1784"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0f766669e768ef9a2b23ecfa710b38b6a48da3f91755113c79320b207ae255d"}, + {file = "bitarray-2.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b6337c0c64044f35ddfb241143244aac707a68f34ae31a71dad115f773ccc8b"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_aarch64.whl", hash = "sha256:731b59540167f8b2b20f69f487ecee2339fc4657059906a16cb51acac17f89c3"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_i686.whl", hash = "sha256:4feed0539a9d6432361fc4d3820eea3a81fa631d542f166cf8430aad81a971da"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_ppc64le.whl", hash = "sha256:eb65c96a42e73f35175ec738d67992ffdf054c20abee3933cfcfa2343fa1187d"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_s390x.whl", hash = "sha256:4f40ceac94d182de6135759d81289683ff3e4cf0da709bc5826a7fe00d754114"}, + {file = "bitarray-2.9.3-cp36-cp36m-musllinux_1_2_x86_64.whl", hash = "sha256:5b29f7844080a281635a231a37e99f0bd6f567af6cf19f4f6d212137f99a9cdf"}, + {file = "bitarray-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:947cf522a3b339b73114d12417fd848fa01303dbaa7883ced4c87688dba5637c"}, + {file = "bitarray-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:ea794ea60d514d68777a87a74106110db7a4bbc2c46720e67010e3071afefb95"}, + {file = "bitarray-2.9.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c7bc7cb79dcac8bdce23b305e671c06eaeffb012fa065b8c33bc51df7e1733f0"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d6380ad0f929ad9220abadd1c9b7234271c4b6ea9c753a88611d489e93a8f2e"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05f4e2451e2ad450b41ede8440e52c1fd798e81027e1dc2256292ec0787d3bf1"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7267885c98138f3707c710d5b08eedef150a3e5112c760cfe1200f3366fd7064"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:976957423cb41df8fe0eb811dbb53d8c5ab1ca3beec7a3ca7ff679be44a72714"}, + {file = "bitarray-2.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c0ec5141a69f73ed6ff17ea7344d5cc166e087095bfe3661dbb42b519e76aa16"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:218a1b7c0652a3c1020f903ded0f9768c3719fb6d43a6e9d346e985292992d35"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:cf0c9ebf2df280794244e1e12ed626357506ddaa2f0d6f69efe493ae7bbf4bf7"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:c450a04a7e091b57d4c0bd1531648522cd0ef26913ad0e5dea0432ea29b0e5c1"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:a212eb89a50e32ef4969387e44a7410447dc59587615e3966d090edc338a1b85"}, + {file = "bitarray-2.9.3-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:4269232026212ee6b73379b88a578107a6b36a6182307a49d5509686c7495261"}, + {file = "bitarray-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:8a0fb358e6a43f216c3fb0871e2ac14c16563aec363c23bc2fbbb18f6201285d"}, + {file = "bitarray-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:a8368774cdc737eec8fce6f28d0abc095fbc0edccf8fab8d29fddc264b68def9"}, + {file = "bitarray-2.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7d0724a4fef6ded914075a3385ea2d05afdeed567902f83490ed4e7e7e75d9bf"}, + {file = "bitarray-2.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0e11b37c6dff6f41ebc49914628824ceb8c8d6ebd0fda2ebe3c0fe0c63e8621e"}, + {file = "bitarray-2.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:085f4081d72c7468f82f722a9f113e03a1f7a4c132ef4c2a4e680c5d78b7db00"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b530b5fbed2900634fbc43f546e384abd72ad9c49795ff5bd6a93cac1aa9c4d8"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09ff88e4385967571146fb0d270442de39393d44198f4d108f3350cfd6486f0b"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a344bb212ddf87db4976a6711d274660a5d887da4fd3faafcdaa092152f85a6d"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc569c96b990f92fd5946d5b50501fee48b01a116a286d1de7961ebd9c6f06f3"}, + {file = "bitarray-2.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2fbbe7938ef8a7abe3e8519fa0578b51d2787f7171d3144e7d373551b5851fd"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0b5912fab904507b47217509b01aa903d7f98b6e725e490a7f01661f4d9a4fa7"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:0c836ccfca9cf60927256738ef234dfe500565492eff269610cdd1bca56801d0"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:af0e4441ebf51c18fc450962f1e201c96f444d63b17cc8dcf7c0b05111bd4486"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:9e9b57175fb6fe76d7ddd0647e06a25f6e23f4b54b5febf337c5a840ab37dc3b"}, + {file = "bitarray-2.9.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:7f7de81721ae9492926bd067007ac974692182bb83fc8f0ba330a67f37a018bd"}, + {file = "bitarray-2.9.3-cp38-cp38-win32.whl", hash = "sha256:4beafb6b6e344385480df6611fdebfcb3579bbb40636ce1ddf5e72fb744e095f"}, + {file = "bitarray-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:d8eaeca98900bd6f06a29cdef57999813a67d314f661d14901d71e04f4cf9f00"}, + {file = "bitarray-2.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:413965d9d384aef90e58b959f4a39f1d5060b145c26080297b7b4cf23cf38faa"}, + {file = "bitarray-2.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2fbb56f2bb89c3a15304a6c0ea56013dc340a98337d9bbd7fc5c21451dc05f8c"}, + {file = "bitarray-2.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b8a84f39f7885627711473872d8fc58fc7a0a1e4ecd9ddf42daf9a3643432742"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45147a9c8580e857c1344d15bd49d2b4387777bd582a2ede11be2ba740653f28"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ed255423dc60c6b2d5c0d90c13dea2962a31929767fdf1c525ab3210269e75c5"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4f5bd02671ea5c4ad52bbfe0e8e8197b6e8fa85dec1e93a4a05448c19354cc65"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1c99c58f044549c93fb6d4cda22678deccaed19845eaa2e6917b5b7ca058f2d"}, + {file = "bitarray-2.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:921ee87681e32e17d1849e11c96eb6a8a7edaa1269dd26831013daf8546bde05"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ed97d8ec40c4658d9f9aa8f26cb473f44fa1dbccba3fa3fbe4a102e38c6a8d7"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9d7f7db37edb9c50c9aad6a18f2e87dd7dc5ff2a33406821804a03263fedb2ca"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:292f726cdb9efc744ed0a1d7453c44151526648148a28d9a2495cc7c7b2c62a8"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2cc94784238782a9376f307b1aa9a85ce77b6eded9f82d2fe062db7fdb02c645"}, + {file = "bitarray-2.9.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5051436b1d318f6ce0df3b2f8a60bfa66a54c1d9e8719d6cb6b448140e7061f2"}, + {file = "bitarray-2.9.3-cp39-cp39-win32.whl", hash = "sha256:a3d436c686ce59fd0b93438ed2c0e1d3e1716e56bce64b874d05b9f49f1ca5d1"}, + {file = "bitarray-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:f168fc45664266a560f2cb28a327041b7f69d4a7faad8ab89e0a1dd7c270a70d"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ae36787299cff41f212aee33cfe1defee13979a41552665a412b6ca3fa8f7eb8"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42afe48abb8eeb386d93e7f1165ace1dd027f136a8a31edd2b20bc57a0c071d7"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451ceecdb86bb95ae101b0d65c8c4524d692ae3666662fef8c89877ce17748c5"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4d67d3e3de2aede737b12cd75a84963700c941b77b579c14bd05517e05d7a9f"}, + {file = "bitarray-2.9.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2406d13ded84049b4238815a5821e44d6f58ba00fbb6b705b6ef8ccd88be8f03"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0db944fc2a048020fc940841ef46c0295b045d45a5a582cba69f78962a49a384"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25c603f141171a7d108773d5136d14e572c473e4cdb3fb464c39c8a138522eb2"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86c06b02705305cab0914d209caa24effda81316e2f2555a71a9aa399b75c5a5"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ddda45b24a802eaaca8f794e6267ff2b62de5fe7b900b76d6f662d95192bebf"}, + {file = "bitarray-2.9.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:81490623950d04870c6dd4d7e6df2eb68dd04eca8bec327895ebee8bbe0cc3c7"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a9e69ac6a514cc574891c24a50847022dac2fef8c3f4df530f92820a07337755"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:545c695ee69d26b41351ced4c76244d8b6225669fc0af3652ff8ed5a6b28325d"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbb2e6daabd2a64d091ac7460b0c5c5f9268199ae9a8ce32737cf5273987f1fa"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a969e5cf63144b944ee8d0a0739f53ef1ae54725b5e01258d690a8995d880526"}, + {file = "bitarray-2.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:73bbb9301ac9000f869c51db2cc5fcc6541985d3fcdcfe6e02f90c9e672a00be"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c07e346926488a85a48542d898f4168f3587ec42379fef0d18be301e08a3f27"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a26d8a14cd8ee496306f2afac34833502dd1ae826355af309333b6f252b23fe"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cef148ed37c892395ca182d6a235524165a9f765f4283d0a1ced891e7c43c67a"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94f35a8f0c8a50ee98a8bef9a070d0b68ecf623f20a2148cc039aba5557346a6"}, + {file = "bitarray-2.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b03207460daae828e2743874c84264e8d96a8c6156490279092b624cd5d2de08"}, + {file = "bitarray-2.9.3.tar.gz", hash = "sha256:9eff55cf189b0c37ba97156a00d640eb7392db58a8049be6f26ff2712b93fa89"}, ] [[package]] @@ -415,78 +428,78 @@ files = [ [[package]] name = "cffi" -version = "1.17.0" +version = "1.17.1" description = "Foreign Function Interface for Python calling C code." optional = false python-versions = ">=3.8" files = [ - {file = "cffi-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb"}, - {file = "cffi-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab"}, - {file = "cffi-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa"}, - {file = "cffi-1.17.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f"}, - {file = "cffi-1.17.0-cp310-cp310-win32.whl", hash = "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc"}, - {file = "cffi-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720"}, - {file = "cffi-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8"}, - {file = "cffi-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8"}, - {file = "cffi-1.17.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb"}, - {file = "cffi-1.17.0-cp311-cp311-win32.whl", hash = "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9"}, - {file = "cffi-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc"}, - {file = "cffi-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828"}, - {file = "cffi-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a"}, - {file = "cffi-1.17.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885"}, - {file = "cffi-1.17.0-cp312-cp312-win32.whl", hash = "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492"}, - {file = "cffi-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118"}, - {file = "cffi-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204"}, - {file = "cffi-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0"}, - {file = "cffi-1.17.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4"}, - {file = "cffi-1.17.0-cp313-cp313-win32.whl", hash = "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a"}, - {file = "cffi-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7"}, - {file = "cffi-1.17.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401"}, - {file = "cffi-1.17.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c"}, - {file = "cffi-1.17.0-cp38-cp38-win32.whl", hash = "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499"}, - {file = "cffi-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c"}, - {file = "cffi-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2"}, - {file = "cffi-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058"}, - {file = "cffi-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3"}, - {file = "cffi-1.17.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4"}, - {file = "cffi-1.17.0-cp39-cp39-win32.whl", hash = "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb"}, - {file = "cffi-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29"}, - {file = "cffi-1.17.0.tar.gz", hash = "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, ] [package.dependencies] @@ -494,101 +507,116 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -709,83 +737,73 @@ requests = "*" [[package]] name = "coverage" -version = "7.6.1" +version = "7.6.7" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, - {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, - {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, - {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, - {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, - {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, - {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, - {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, - {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, - {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, - {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, - {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, - {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, - {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, - {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, - {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, + {file = "coverage-7.6.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:108bb458827765d538abcbf8288599fee07d2743357bdd9b9dad456c287e121e"}, + {file = "coverage-7.6.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c973b2fe4dc445cb865ab369df7521df9c27bf40715c837a113edaa2aa9faf45"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c6b24007c4bcd0b19fac25763a7cac5035c735ae017e9a349b927cfc88f31c1"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:acbb8af78f8f91b3b51f58f288c0994ba63c646bc1a8a22ad072e4e7e0a49f1c"}, + {file = "coverage-7.6.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad32a981bcdedb8d2ace03b05e4fd8dace8901eec64a532b00b15217d3677dd2"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:34d23e28ccb26236718a3a78ba72744212aa383141961dd6825f6595005c8b06"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e25bacb53a8c7325e34d45dddd2f2fbae0dbc230d0e2642e264a64e17322a777"}, + {file = "coverage-7.6.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af05bbba896c4472a29408455fe31b3797b4d8648ed0a2ccac03e074a77e2314"}, + {file = "coverage-7.6.7-cp310-cp310-win32.whl", hash = "sha256:796c9b107d11d2d69e1849b2dfe41730134b526a49d3acb98ca02f4985eeff7a"}, + {file = "coverage-7.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:987a8e3da7da4eed10a20491cf790589a8e5e07656b6dc22d3814c4d88faf163"}, + {file = "coverage-7.6.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7e61b0e77ff4dddebb35a0e8bb5a68bf0f8b872407d8d9f0c726b65dfabe2469"}, + {file = "coverage-7.6.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1a5407a75ca4abc20d6252efeb238377a71ce7bda849c26c7a9bece8680a5d99"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df002e59f2d29e889c37abd0b9ee0d0e6e38c24f5f55d71ff0e09e3412a340ec"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:673184b3156cba06154825f25af33baa2671ddae6343f23175764e65a8c4c30b"}, + {file = "coverage-7.6.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e69ad502f1a2243f739f5bd60565d14a278be58be4c137d90799f2c263e7049a"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:60dcf7605c50ea72a14490d0756daffef77a5be15ed1b9fea468b1c7bda1bc3b"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9c2eb378bebb2c8f65befcb5147877fc1c9fbc640fc0aad3add759b5df79d55d"}, + {file = "coverage-7.6.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c0317288f032221d35fa4cbc35d9f4923ff0dfd176c79c9b356e8ef8ef2dff4"}, + {file = "coverage-7.6.7-cp311-cp311-win32.whl", hash = "sha256:951aade8297358f3618a6e0660dc74f6b52233c42089d28525749fc8267dccd2"}, + {file = "coverage-7.6.7-cp311-cp311-win_amd64.whl", hash = "sha256:5e444b8e88339a2a67ce07d41faabb1d60d1004820cee5a2c2b54e2d8e429a0f"}, + {file = "coverage-7.6.7-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f07ff574986bc3edb80e2c36391678a271d555f91fd1d332a1e0f4b5ea4b6ea9"}, + {file = "coverage-7.6.7-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:49ed5ee4109258973630c1f9d099c7e72c5c36605029f3a91fe9982c6076c82b"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3e8796434a8106b3ac025fd15417315d7a58ee3e600ad4dbcfddc3f4b14342c"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3b925300484a3294d1c70f6b2b810d6526f2929de954e5b6be2bf8caa1f12c1"}, + {file = "coverage-7.6.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c42ec2c522e3ddd683dec5cdce8e62817afb648caedad9da725001fa530d354"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0266b62cbea568bd5e93a4da364d05de422110cbed5056d69339bd5af5685433"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e5f2a0f161d126ccc7038f1f3029184dbdf8f018230af17ef6fd6a707a5b881f"}, + {file = "coverage-7.6.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c132b5a22821f9b143f87446805e13580b67c670a548b96da945a8f6b4f2efbb"}, + {file = "coverage-7.6.7-cp312-cp312-win32.whl", hash = "sha256:7c07de0d2a110f02af30883cd7dddbe704887617d5c27cf373362667445a4c76"}, + {file = "coverage-7.6.7-cp312-cp312-win_amd64.whl", hash = "sha256:fd49c01e5057a451c30c9b892948976f5d38f2cbd04dc556a82743ba8e27ed8c"}, + {file = "coverage-7.6.7-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46f21663e358beae6b368429ffadf14ed0a329996248a847a4322fb2e35d64d3"}, + {file = "coverage-7.6.7-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40cca284c7c310d622a1677f105e8507441d1bb7c226f41978ba7c86979609ab"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77256ad2345c29fe59ae861aa11cfc74579c88d4e8dbf121cbe46b8e32aec808"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87ea64b9fa52bf395272e54020537990a28078478167ade6c61da7ac04dc14bc"}, + {file = "coverage-7.6.7-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d608a7808793e3615e54e9267519351c3ae204a6d85764d8337bd95993581a8"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdd94501d65adc5c24f8a1a0eda110452ba62b3f4aeaba01e021c1ed9cb8f34a"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:82c809a62e953867cf57e0548c2b8464207f5f3a6ff0e1e961683e79b89f2c55"}, + {file = "coverage-7.6.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:bb684694e99d0b791a43e9fc0fa58efc15ec357ac48d25b619f207c41f2fd384"}, + {file = "coverage-7.6.7-cp313-cp313-win32.whl", hash = "sha256:963e4a08cbb0af6623e61492c0ec4c0ec5c5cf74db5f6564f98248d27ee57d30"}, + {file = "coverage-7.6.7-cp313-cp313-win_amd64.whl", hash = "sha256:14045b8bfd5909196a90da145a37f9d335a5d988a83db34e80f41e965fb7cb42"}, + {file = "coverage-7.6.7-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f2c7a045eef561e9544359a0bf5784b44e55cefc7261a20e730baa9220c83413"}, + {file = "coverage-7.6.7-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5dd4e4a49d9c72a38d18d641135d2fb0bdf7b726ca60a103836b3d00a1182acd"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c95e0fa3d1547cb6f021ab72f5c23402da2358beec0a8e6d19a368bd7b0fb37"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f63e21ed474edd23f7501f89b53280014436e383a14b9bd77a648366c81dce7b"}, + {file = "coverage-7.6.7-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead9b9605c54d15be228687552916c89c9683c215370c4a44f1f217d2adcc34d"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:0573f5cbf39114270842d01872952d301027d2d6e2d84013f30966313cadb529"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:e2c8e3384c12dfa19fa9a52f23eb091a8fad93b5b81a41b14c17c78e23dd1d8b"}, + {file = "coverage-7.6.7-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:70a56a2ec1869e6e9fa69ef6b76b1a8a7ef709972b9cc473f9ce9d26b5997ce3"}, + {file = "coverage-7.6.7-cp313-cp313t-win32.whl", hash = "sha256:dbba8210f5067398b2c4d96b4e64d8fb943644d5eb70be0d989067c8ca40c0f8"}, + {file = "coverage-7.6.7-cp313-cp313t-win_amd64.whl", hash = "sha256:dfd14bcae0c94004baba5184d1c935ae0d1231b8409eb6c103a5fd75e8ecdc56"}, + {file = "coverage-7.6.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37a15573f988b67f7348916077c6d8ad43adb75e478d0910957394df397d2874"}, + {file = "coverage-7.6.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b6cce5c76985f81da3769c52203ee94722cd5d5889731cd70d31fee939b74bf0"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ab9763d291a17b527ac6fd11d1a9a9c358280adb320e9c2672a97af346ac2c"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6cf96ceaa275f071f1bea3067f8fd43bec184a25a962c754024c973af871e1b7"}, + {file = "coverage-7.6.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aee9cf6b0134d6f932d219ce253ef0e624f4fa588ee64830fcba193269e4daa3"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2bc3e45c16564cc72de09e37413262b9f99167803e5e48c6156bccdfb22c8327"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:623e6965dcf4e28a3debaa6fcf4b99ee06d27218f46d43befe4db1c70841551c"}, + {file = "coverage-7.6.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:850cfd2d6fc26f8346f422920ac204e1d28814e32e3a58c19c91980fa74d8289"}, + {file = "coverage-7.6.7-cp39-cp39-win32.whl", hash = "sha256:c296263093f099da4f51b3dff1eff5d4959b527d4f2f419e16508c5da9e15e8c"}, + {file = "coverage-7.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:90746521206c88bdb305a4bf3342b1b7316ab80f804d40c536fc7d329301ee13"}, + {file = "coverage-7.6.7-pp39.pp310-none-any.whl", hash = "sha256:0ddcb70b3a3a57581b450571b31cb774f23eb9519c2aaa6176d3a84c9fc57671"}, + {file = "coverage-7.6.7.tar.gz", hash = "sha256:d79d4826e41441c9a118ff045e4bccb9fdbdcb1d02413e7ea6eb5c87b5439d24"}, ] [package.extras] @@ -793,38 +811,38 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, - {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, - {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, - {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, - {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, - {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, - {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, ] [package.dependencies] @@ -837,7 +855,7 @@ nox = ["nox"] pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -979,13 +997,13 @@ optimize = ["orjson"] [[package]] name = "distlib" -version = "0.3.8" +version = "0.3.9" description = "Distribution utilities" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {file = "distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87"}, + {file = "distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403"}, ] [[package]] @@ -1276,19 +1294,19 @@ all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)" [[package]] name = "filelock" -version = "3.15.4" +version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"}, - {file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"] -typing = ["typing-extensions (>=4.8)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "flask" @@ -1400,13 +1418,13 @@ files = [ [[package]] name = "googleapis-common-protos" -version = "1.65.0" +version = "1.66.0" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis_common_protos-1.65.0-py2.py3-none-any.whl", hash = "sha256:2972e6c496f435b92590fd54045060867f3fe9be2c82ab148fc8885035479a63"}, - {file = "googleapis_common_protos-1.65.0.tar.gz", hash = "sha256:334a29d07cddc3aa01dee4988f9afd9b2916ee2ff49d6b757155dc0d197852c0"}, + {file = "googleapis_common_protos-1.66.0-py2.py3-none-any.whl", hash = "sha256:d7abcd75fabb2e0ec9f74466401f6c119a0b498e27370e9be4c94cb7e382b8ed"}, + {file = "googleapis_common_protos-1.66.0.tar.gz", hash = "sha256:c3e7b33d15fdca5374cc0a7346dd92ffa847425cc4ea941d970f13680052ec8c"}, ] [package.dependencies] @@ -1445,72 +1463,84 @@ websockets = ["websockets (>=10,<12)"] [[package]] name = "graphql-core" -version = "3.2.3" +version = "3.2.5" description = "GraphQL implementation for Python, a port of GraphQL.js, the JavaScript reference implementation for GraphQL." optional = false -python-versions = ">=3.6,<4" +python-versions = "<4,>=3.6" files = [ - {file = "graphql-core-3.2.3.tar.gz", hash = "sha256:06d2aad0ac723e35b1cb47885d3e5c45e956a53bc1b209a9fc5369007fe46676"}, - {file = "graphql_core-3.2.3-py3-none-any.whl", hash = "sha256:5766780452bd5ec8ba133f8bf287dc92713e3868ddd83aee4faab9fc3e303dc3"}, + {file = "graphql_core-3.2.5-py3-none-any.whl", hash = "sha256:2f150d5096448aa4f8ab26268567bbfeef823769893b39c1a2e1409590939c8a"}, + {file = "graphql_core-3.2.5.tar.gz", hash = "sha256:e671b90ed653c808715645e3998b7ab67d382d55467b7e2978549111bbabf8d5"}, ] +[package.dependencies] +typing-extensions = {version = ">=4,<5", markers = "python_version < \"3.10\""} + [[package]] name = "grpcio" -version = "1.66.1" +version = "1.68.0" description = "HTTP/2-based RPC framework" optional = false python-versions = ">=3.8" files = [ - {file = "grpcio-1.66.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:4877ba180591acdf127afe21ec1c7ff8a5ecf0fe2600f0d3c50e8c4a1cbc6492"}, - {file = "grpcio-1.66.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:3750c5a00bd644c75f4507f77a804d0189d97a107eb1481945a0cf3af3e7a5ac"}, - {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:a013c5fbb12bfb5f927444b477a26f1080755a931d5d362e6a9a720ca7dbae60"}, - {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1b24c23d51a1e8790b25514157d43f0a4dce1ac12b3f0b8e9f66a5e2c4c132f"}, - {file = "grpcio-1.66.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7ffb8ea674d68de4cac6f57d2498fef477cef582f1fa849e9f844863af50083"}, - {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:307b1d538140f19ccbd3aed7a93d8f71103c5d525f3c96f8616111614b14bf2a"}, - {file = "grpcio-1.66.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1c17ebcec157cfb8dd445890a03e20caf6209a5bd4ac5b040ae9dbc59eef091d"}, - {file = "grpcio-1.66.1-cp310-cp310-win32.whl", hash = "sha256:ef82d361ed5849d34cf09105d00b94b6728d289d6b9235513cb2fcc79f7c432c"}, - {file = "grpcio-1.66.1-cp310-cp310-win_amd64.whl", hash = "sha256:292a846b92cdcd40ecca46e694997dd6b9be6c4c01a94a0dfb3fcb75d20da858"}, - {file = "grpcio-1.66.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:c30aeceeaff11cd5ddbc348f37c58bcb96da8d5aa93fed78ab329de5f37a0d7a"}, - {file = "grpcio-1.66.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8a1e224ce6f740dbb6b24c58f885422deebd7eb724aff0671a847f8951857c26"}, - {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a66fe4dc35d2330c185cfbb42959f57ad36f257e0cc4557d11d9f0a3f14311df"}, - {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ba04659e4fce609de2658fe4dbf7d6ed21987a94460f5f92df7579fd5d0e22"}, - {file = "grpcio-1.66.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4573608e23f7e091acfbe3e84ac2045680b69751d8d67685ffa193a4429fedb1"}, - {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7e06aa1f764ec8265b19d8f00140b8c4b6ca179a6dc67aa9413867c47e1fb04e"}, - {file = "grpcio-1.66.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3885f037eb11f1cacc41f207b705f38a44b69478086f40608959bf5ad85826dd"}, - {file = "grpcio-1.66.1-cp311-cp311-win32.whl", hash = "sha256:97ae7edd3f3f91480e48ede5d3e7d431ad6005bfdbd65c1b56913799ec79e791"}, - {file = "grpcio-1.66.1-cp311-cp311-win_amd64.whl", hash = "sha256:cfd349de4158d797db2bd82d2020554a121674e98fbe6b15328456b3bf2495bb"}, - {file = "grpcio-1.66.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:a92c4f58c01c77205df6ff999faa008540475c39b835277fb8883b11cada127a"}, - {file = "grpcio-1.66.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fdb14bad0835914f325349ed34a51940bc2ad965142eb3090081593c6e347be9"}, - {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f03a5884c56256e08fd9e262e11b5cfacf1af96e2ce78dc095d2c41ccae2c80d"}, - {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ca2559692d8e7e245d456877a85ee41525f3ed425aa97eb7a70fc9a79df91a0"}, - {file = "grpcio-1.66.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84ca1be089fb4446490dd1135828bd42a7c7f8421e74fa581611f7afdf7ab761"}, - {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:d639c939ad7c440c7b2819a28d559179a4508783f7e5b991166f8d7a34b52815"}, - {file = "grpcio-1.66.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b9feb4e5ec8dc2d15709f4d5fc367794d69277f5d680baf1910fc9915c633524"}, - {file = "grpcio-1.66.1-cp312-cp312-win32.whl", hash = "sha256:7101db1bd4cd9b880294dec41a93fcdce465bdbb602cd8dc5bd2d6362b618759"}, - {file = "grpcio-1.66.1-cp312-cp312-win_amd64.whl", hash = "sha256:b0aa03d240b5539648d996cc60438f128c7f46050989e35b25f5c18286c86734"}, - {file = "grpcio-1.66.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:ecfe735e7a59e5a98208447293ff8580e9db1e890e232b8b292dc8bd15afc0d2"}, - {file = "grpcio-1.66.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:4825a3aa5648010842e1c9d35a082187746aa0cdbf1b7a2a930595a94fb10fce"}, - {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:f517fd7259fe823ef3bd21e508b653d5492e706e9f0ef82c16ce3347a8a5620c"}, - {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1fe60d0772831d96d263b53d83fb9a3d050a94b0e94b6d004a5ad111faa5b5b"}, - {file = "grpcio-1.66.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31a049daa428f928f21090403e5d18ea02670e3d5d172581670be006100db9ef"}, - {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f914386e52cbdeb5d2a7ce3bf1fdfacbe9d818dd81b6099a05b741aaf3848bb"}, - {file = "grpcio-1.66.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:bff2096bdba686019fb32d2dde45b95981f0d1490e054400f70fc9a8af34b49d"}, - {file = "grpcio-1.66.1-cp38-cp38-win32.whl", hash = "sha256:aa8ba945c96e73de29d25331b26f3e416e0c0f621e984a3ebdb2d0d0b596a3b3"}, - {file = "grpcio-1.66.1-cp38-cp38-win_amd64.whl", hash = "sha256:161d5c535c2bdf61b95080e7f0f017a1dfcb812bf54093e71e5562b16225b4ce"}, - {file = "grpcio-1.66.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:d0cd7050397b3609ea51727b1811e663ffda8bda39c6a5bb69525ef12414b503"}, - {file = "grpcio-1.66.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0e6c9b42ded5d02b6b1fea3a25f036a2236eeb75d0579bfd43c0018c88bf0a3e"}, - {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:c9f80f9fad93a8cf71c7f161778ba47fd730d13a343a46258065c4deb4b550c0"}, - {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5dd67ed9da78e5121efc5c510f0122a972216808d6de70953a740560c572eb44"}, - {file = "grpcio-1.66.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48b0d92d45ce3be2084b92fb5bae2f64c208fea8ceed7fccf6a7b524d3c4942e"}, - {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4d813316d1a752be6f5c4360c49f55b06d4fe212d7df03253dfdae90c8a402bb"}, - {file = "grpcio-1.66.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9c9bebc6627873ec27a70fc800f6083a13c70b23a5564788754b9ee52c5aef6c"}, - {file = "grpcio-1.66.1-cp39-cp39-win32.whl", hash = "sha256:30a1c2cf9390c894c90bbc70147f2372130ad189cffef161f0432d0157973f45"}, - {file = "grpcio-1.66.1-cp39-cp39-win_amd64.whl", hash = "sha256:17663598aadbedc3cacd7bbde432f541c8e07d2496564e22b214b22c7523dac8"}, - {file = "grpcio-1.66.1.tar.gz", hash = "sha256:35334f9c9745add3e357e3372756fd32d925bd52c41da97f4dfdafbde0bf0ee2"}, + {file = "grpcio-1.68.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:619b5d0f29f4f5351440e9343224c3e19912c21aeda44e0c49d0d147a8d01544"}, + {file = "grpcio-1.68.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:a59f5822f9459bed098ffbceb2713abbf7c6fd13f2b9243461da5c338d0cd6c3"}, + {file = "grpcio-1.68.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:c03d89df516128febc5a7e760d675b478ba25802447624edf7aa13b1e7b11e2a"}, + {file = "grpcio-1.68.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44bcbebb24363d587472089b89e2ea0ab2e2b4df0e4856ba4c0b087c82412121"}, + {file = "grpcio-1.68.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79f81b7fbfb136247b70465bd836fa1733043fdee539cd6031cb499e9608a110"}, + {file = "grpcio-1.68.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:88fb2925789cfe6daa20900260ef0a1d0a61283dfb2d2fffe6194396a354c618"}, + {file = "grpcio-1.68.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:99f06232b5c9138593ae6f2e355054318717d32a9c09cdc5a2885540835067a1"}, + {file = "grpcio-1.68.0-cp310-cp310-win32.whl", hash = "sha256:a6213d2f7a22c3c30a479fb5e249b6b7e648e17f364598ff64d08a5136fe488b"}, + {file = "grpcio-1.68.0-cp310-cp310-win_amd64.whl", hash = "sha256:15327ab81131ef9b94cb9f45b5bd98803a179c7c61205c8c0ac9aff9d6c4e82a"}, + {file = "grpcio-1.68.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:3b2b559beb2d433129441783e5f42e3be40a9e1a89ec906efabf26591c5cd415"}, + {file = "grpcio-1.68.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e46541de8425a4d6829ac6c5d9b16c03c292105fe9ebf78cb1c31e8d242f9155"}, + {file = "grpcio-1.68.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:c1245651f3c9ea92a2db4f95d37b7597db6b246d5892bca6ee8c0e90d76fb73c"}, + {file = "grpcio-1.68.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f1931c7aa85be0fa6cea6af388e576f3bf6baee9e5d481c586980c774debcb4"}, + {file = "grpcio-1.68.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b0ff09c81e3aded7a183bc6473639b46b6caa9c1901d6f5e2cba24b95e59e30"}, + {file = "grpcio-1.68.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8c73f9fbbaee1a132487e31585aa83987ddf626426d703ebcb9a528cf231c9b1"}, + {file = "grpcio-1.68.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6b2f98165ea2790ea159393a2246b56f580d24d7da0d0342c18a085299c40a75"}, + {file = "grpcio-1.68.0-cp311-cp311-win32.whl", hash = "sha256:e1e7ed311afb351ff0d0e583a66fcb39675be112d61e7cfd6c8269884a98afbc"}, + {file = "grpcio-1.68.0-cp311-cp311-win_amd64.whl", hash = "sha256:e0d2f68eaa0a755edd9a47d40e50dba6df2bceda66960dee1218da81a2834d27"}, + {file = "grpcio-1.68.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8af6137cc4ae8e421690d276e7627cfc726d4293f6607acf9ea7260bd8fc3d7d"}, + {file = "grpcio-1.68.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4028b8e9a3bff6f377698587d642e24bd221810c06579a18420a17688e421af7"}, + {file = "grpcio-1.68.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f60fa2adf281fd73ae3a50677572521edca34ba373a45b457b5ebe87c2d01e1d"}, + {file = "grpcio-1.68.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e18589e747c1e70b60fab6767ff99b2d0c359ea1db8a2cb524477f93cdbedf5b"}, + {file = "grpcio-1.68.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0d30f3fee9372796f54d3100b31ee70972eaadcc87314be369360248a3dcffe"}, + {file = "grpcio-1.68.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:7e0a3e72c0e9a1acab77bef14a73a416630b7fd2cbd893c0a873edc47c42c8cd"}, + {file = "grpcio-1.68.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a831dcc343440969aaa812004685ed322cdb526cd197112d0db303b0da1e8659"}, + {file = "grpcio-1.68.0-cp312-cp312-win32.whl", hash = "sha256:5a180328e92b9a0050958ced34dddcb86fec5a8b332f5a229e353dafc16cd332"}, + {file = "grpcio-1.68.0-cp312-cp312-win_amd64.whl", hash = "sha256:2bddd04a790b69f7a7385f6a112f46ea0b34c4746f361ebafe9ca0be567c78e9"}, + {file = "grpcio-1.68.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:fc05759ffbd7875e0ff2bd877be1438dfe97c9312bbc558c8284a9afa1d0f40e"}, + {file = "grpcio-1.68.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:15fa1fe25d365a13bc6d52fcac0e3ee1f9baebdde2c9b3b2425f8a4979fccea1"}, + {file = "grpcio-1.68.0-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:32a9cb4686eb2e89d97022ecb9e1606d132f85c444354c17a7dbde4a455e4a3b"}, + {file = "grpcio-1.68.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dba037ff8d284c8e7ea9a510c8ae0f5b016004f13c3648f72411c464b67ff2fb"}, + {file = "grpcio-1.68.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0efbbd849867e0e569af09e165363ade75cf84f5229b2698d53cf22c7a4f9e21"}, + {file = "grpcio-1.68.0-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:4e300e6978df0b65cc2d100c54e097c10dfc7018b9bd890bbbf08022d47f766d"}, + {file = "grpcio-1.68.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:6f9c7ad1a23e1047f827385f4713b5b8c6c7d325705be1dd3e31fb00dcb2f665"}, + {file = "grpcio-1.68.0-cp313-cp313-win32.whl", hash = "sha256:3ac7f10850fd0487fcce169c3c55509101c3bde2a3b454869639df2176b60a03"}, + {file = "grpcio-1.68.0-cp313-cp313-win_amd64.whl", hash = "sha256:afbf45a62ba85a720491bfe9b2642f8761ff348006f5ef67e4622621f116b04a"}, + {file = "grpcio-1.68.0-cp38-cp38-linux_armv7l.whl", hash = "sha256:f8f695d9576ce836eab27ba7401c60acaf9ef6cf2f70dfe5462055ba3df02cc3"}, + {file = "grpcio-1.68.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9fe1b141cda52f2ca73e17d2d3c6a9f3f3a0c255c216b50ce616e9dca7e3441d"}, + {file = "grpcio-1.68.0-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:4df81d78fd1646bf94ced4fb4cd0a7fe2e91608089c522ef17bc7db26e64effd"}, + {file = "grpcio-1.68.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46a2d74d4dd8993151c6cd585594c082abe74112c8e4175ddda4106f2ceb022f"}, + {file = "grpcio-1.68.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a17278d977746472698460c63abf333e1d806bd41f2224f90dbe9460101c9796"}, + {file = "grpcio-1.68.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:15377bce516b1c861c35e18eaa1c280692bf563264836cece693c0f169b48829"}, + {file = "grpcio-1.68.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:cc5f0a4f5904b8c25729a0498886b797feb817d1fd3812554ffa39551112c161"}, + {file = "grpcio-1.68.0-cp38-cp38-win32.whl", hash = "sha256:def1a60a111d24376e4b753db39705adbe9483ef4ca4761f825639d884d5da78"}, + {file = "grpcio-1.68.0-cp38-cp38-win_amd64.whl", hash = "sha256:55d3b52fd41ec5772a953612db4e70ae741a6d6ed640c4c89a64f017a1ac02b5"}, + {file = "grpcio-1.68.0-cp39-cp39-linux_armv7l.whl", hash = "sha256:0d230852ba97654453d290e98d6aa61cb48fa5fafb474fb4c4298d8721809354"}, + {file = "grpcio-1.68.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:50992f214264e207e07222703c17d9cfdcc2c46ed5a1ea86843d440148ebbe10"}, + {file = "grpcio-1.68.0-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:14331e5c27ed3545360464a139ed279aa09db088f6e9502e95ad4bfa852bb116"}, + {file = "grpcio-1.68.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f84890b205692ea813653ece4ac9afa2139eae136e419231b0eec7c39fdbe4c2"}, + {file = "grpcio-1.68.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0cf343c6f4f6aa44863e13ec9ddfe299e0be68f87d68e777328bff785897b05"}, + {file = "grpcio-1.68.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fd2c2d47969daa0e27eadaf15c13b5e92605c5e5953d23c06d0b5239a2f176d3"}, + {file = "grpcio-1.68.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:18668e36e7f4045820f069997834e94e8275910b1f03e078a6020bd464cb2363"}, + {file = "grpcio-1.68.0-cp39-cp39-win32.whl", hash = "sha256:2af76ab7c427aaa26aa9187c3e3c42f38d3771f91a20f99657d992afada2294a"}, + {file = "grpcio-1.68.0-cp39-cp39-win_amd64.whl", hash = "sha256:e694b5928b7b33ca2d3b4d5f9bf8b5888906f181daff6b406f4938f3a997a490"}, + {file = "grpcio-1.68.0.tar.gz", hash = "sha256:7e7483d39b4a4fddb9906671e9ea21aaad4f031cdfc349fec76bdfa1e404543a"}, ] [package.extras] -protobuf = ["grpcio-tools (>=1.66.1)"] +protobuf = ["grpcio-tools (>=1.68.0)"] [[package]] name = "h11" @@ -1542,33 +1572,40 @@ test = ["eth-utils (>=1.0.1,<3)", "hypothesis (>=3.44.24,<=6.31.6)", "pytest (>= [[package]] name = "idna" -version = "3.8" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "importlib-metadata" -version = "8.4.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, - {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -1752,71 +1789,72 @@ altgraph = ">=0.17" [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] @@ -1961,18 +1999,18 @@ nicer-shell = ["ipython"] [[package]] name = "open-aea" -version = "1.53.0" +version = "1.57.0" description = "Open Autonomous Economic Agent framework (without vendor lock-in)" optional = false python-versions = ">=3.8" files = [ - {file = "open_aea-1.53.0-py3-none-any.whl", hash = "sha256:1244855875effe09e2c965750ac401a973a1ae56cdc880045eea70f19ed90dcb"}, - {file = "open_aea-1.53.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:d0a848e33798599953dc764d37083fc37642140a91624e06a56b8d2f95ae6cb9"}, - {file = "open_aea-1.53.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:48f5715f13a0389799b9461bc776e9638e6ae38173d0f2bf6d28bad637232914"}, - {file = "open_aea-1.53.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:87e4ae903ec9a7268eba0ead449f9693cb5bedb6dfc5846c90f94f2354bd35ab"}, - {file = "open_aea-1.53.0-py3-none-win32.whl", hash = "sha256:182e9f8a77fe8efcc768360ac7308a0951ec16bcb12e2ad4f55886b12258d702"}, - {file = "open_aea-1.53.0-py3-none-win_amd64.whl", hash = "sha256:cef9d4d177ea7d959ebacab962fbd1d03d7243c0b72d10a3ee7850df8d922e06"}, - {file = "open_aea-1.53.0.tar.gz", hash = "sha256:6fcb82ceed0b6841c0f41d116b207308556e3d18807fe140e9ef1a898c7a8a0b"}, + {file = "open_aea-1.57.0-py3-none-any.whl", hash = "sha256:19714577414fa7ce7c9a43e4dd9d7849189b77b158a3d60e75cb43a7ea0eecd5"}, + {file = "open_aea-1.57.0-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:a56d0b6dfa5bcdcf24d0edd167bf0e90c205bb6f20b59bcee0975a8dbd1811fe"}, + {file = "open_aea-1.57.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:a03df0c0e8354a8a0d940969252dbdf633f9b5698ce499e1cd30f694f7635151"}, + {file = "open_aea-1.57.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:1fb3c78c7877bcd41d33b3bd5ee51f2cfe62efa2a07f193838133c771fff5237"}, + {file = "open_aea-1.57.0-py3-none-win32.whl", hash = "sha256:a068d8710d3e235499ae866d167825bca1b56314f255b05591b2e362c1f9b3a6"}, + {file = "open_aea-1.57.0-py3-none-win_amd64.whl", hash = "sha256:eb2ef61a7e7d74f4b99fc27fdbad7350320c18528f85678fe1a6503736ef2de5"}, + {file = "open_aea-1.57.0.tar.gz", hash = "sha256:7cef260f56a4214752ea6242d43cf20a7488815f7e2de53ff2836b57a650a385"}, ] [package.dependencies] @@ -2000,13 +2038,13 @@ test-tools = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "jsonschema (>= [[package]] name = "open-aea-cli-ipfs" -version = "1.53.0" +version = "1.57.0" description = "CLI extension for open AEA framework wrapping IPFS functionality." optional = false python-versions = "*" files = [ - {file = "open_aea_cli_ipfs-1.53.0-py3-none-any.whl", hash = "sha256:335a02473d1c6820bb63a31e2931749ba644f586a7acbc650da9efc4c7168efa"}, - {file = "open_aea_cli_ipfs-1.53.0.tar.gz", hash = "sha256:499a66a45925064e6946ec72f482182390263cc7726409832f1317fe831b6289"}, + {file = "open_aea_cli_ipfs-1.57.0-py3-none-any.whl", hash = "sha256:6cbefd42a682f1f0c116e527f728998f61a9bc930995acdd754b5335e54ad97d"}, + {file = "open_aea_cli_ipfs-1.57.0.tar.gz", hash = "sha256:8254a1ecef4e7e3dbc9ba990243413963a0d5055b336c1ce6f2e0ae4ddaa25ce"}, ] [package.dependencies] @@ -2031,13 +2069,13 @@ web3 = ">=6.0.0,<7" [[package]] name = "open-aea-ledger-cosmos" -version = "1.53.0" +version = "1.57.0" description = "Python package wrapping the public and private key cryptography and ledger api of Cosmos." optional = false python-versions = "*" files = [ - {file = "open_aea_ledger_cosmos-1.53.0-py3-none-any.whl", hash = "sha256:79b2eafc8723593634b72973da39e3e3c01bceae04b330b51a5059eb1200262b"}, - {file = "open_aea_ledger_cosmos-1.53.0.tar.gz", hash = "sha256:14a032918d7f0659fedbe21a53fa668b24505bb9e97358340b20325943f9fa26"}, + {file = "open_aea_ledger_cosmos-1.57.0-py3-none-any.whl", hash = "sha256:dfedc58ae4cebd938b51834f3eca5e2c8ffce95661a84212c3c4b6341e8952d4"}, + {file = "open_aea_ledger_cosmos-1.57.0.tar.gz", hash = "sha256:35ae99e188a256bfcb06d510d161643922d6ed1e639eed92b3b5f7ee3576d5bf"}, ] [package.dependencies] @@ -2049,13 +2087,13 @@ pycryptodome = ">=3.10.1,<4.0.0" [[package]] name = "open-aea-ledger-ethereum" -version = "1.53.0" +version = "1.57.0" description = "Python package wrapping the public and private key cryptography and ledger api of Ethereum." optional = false python-versions = "*" files = [ - {file = "open_aea_ledger_ethereum-1.53.0-py3-none-any.whl", hash = "sha256:501eb9e9e228552bf9f6f8811d780f33dbbf477ddb33b63d335caaeb24840274"}, - {file = "open_aea_ledger_ethereum-1.53.0.tar.gz", hash = "sha256:734f335061c33a171b945ab1bcea5d47be9b9532457ed361b3aab727e85bca0d"}, + {file = "open_aea_ledger_ethereum-1.57.0-py3-none-any.whl", hash = "sha256:8ad775344baa77fc6b8e5a92edfa6d7e32f3361a885113379733e7ce4e4d6405"}, + {file = "open_aea_ledger_ethereum-1.57.0.tar.gz", hash = "sha256:7c16858ad751db3906ec72046c821ad5b057c5e47edbc951da99c52714fb8c5e"}, ] [package.dependencies] @@ -2066,28 +2104,28 @@ web3 = ">=6.0.0,<7" [[package]] name = "open-aea-ledger-ethereum-flashbots" -version = "1.53.0" +version = "1.57.0" description = "Python package extending the default open-aea ethereum ledger plugin to add support for flashbots." optional = false python-versions = "<4.0,>=3.9" files = [ - {file = "open_aea_ledger_ethereum_flashbots-1.53.0-py3-none-any.whl", hash = "sha256:04e1d04b68159f092dbe8c94d419221ad45bac17497c8feed9cbe92270a675b3"}, - {file = "open_aea_ledger_ethereum_flashbots-1.53.0.tar.gz", hash = "sha256:683e0c73c04413a0098f4903e3afa8c1570f8c51591ad6cef66fd38cfad463d8"}, + {file = "open_aea_ledger_ethereum_flashbots-1.57.0-py3-none-any.whl", hash = "sha256:cab2988933fb0196e04b4efe665fb8cb07cd10866a2a37969fac1bad51094cff"}, + {file = "open_aea_ledger_ethereum_flashbots-1.57.0.tar.gz", hash = "sha256:1ce8d8028383a62c0a759936c20af6cc58e594b1bb9dd8a93add2905dafd6511"}, ] [package.dependencies] open-aea-flashbots = "1.4.0" -open-aea-ledger-ethereum = ">=1.53.0,<1.54.0" +open-aea-ledger-ethereum = ">=1.57.0,<1.58.0" [[package]] name = "open-autonomy" -version = "0.14.14.post2" +version = "0.16.1" description = "A framework for the creation of autonomous agent services." optional = false python-versions = ">=3.8" files = [ - {file = "open_autonomy-0.14.14.post2-py3-none-any.whl", hash = "sha256:76efc0ce814c748eb02176477eef5b5ca4c6a84d77230e01a40c3df5ad2254b8"}, - {file = "open_autonomy-0.14.14.post2.tar.gz", hash = "sha256:0e1e7f3207fde38b8778a260c43153737a3b9fefe6d7abf373710a1aae9e267b"}, + {file = "open_autonomy-0.16.1-py3-none-any.whl", hash = "sha256:fec8611e0730d24debf53ed1f6a238a178eb8afc6ada422fbbb027b628e5ef72"}, + {file = "open_autonomy-0.16.1.tar.gz", hash = "sha256:bc670251a5d5859a807f9a7f5a1437c073a0a4b4060378f713a63d6fcb6930e7"}, ] [package.dependencies] @@ -2099,8 +2137,8 @@ Flask = ">=2.0.2,<3.0.0" gql = "3.5.0" hexbytes = "*" jsonschema = ">=4.3.0,<4.4.0" -open-aea = {version = "1.53.0", extras = ["all"]} -open-aea-cli-ipfs = "1.53.0" +open-aea = {version = "1.57.0", extras = ["all"]} +open-aea-cli-ipfs = "1.57.0" protobuf = ">=4.21.6,<4.25.0" pytest = "7.2.1" python-dotenv = ">=0.14.5,<0.22.0" @@ -2113,8 +2151,8 @@ watchdog = ">=2.1.6" werkzeug = "2.0.3" [package.extras] -all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.53.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] -cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.53.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +all = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.57.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] +cli = ["click (>=8.1.0,<9)", "coverage (>=6.4.4,<8.0.0)", "open-aea-cli-ipfs (==1.57.0)", "pytest (>=7.0.0,<7.3.0)", "python-dotenv (>=0.14.5,<0.22.0)", "texttable (==1.6.7)"] [[package]] name = "orderly-set" @@ -2140,13 +2178,13 @@ files = [ [[package]] name = "paramiko" -version = "3.4.1" +version = "3.5.0" description = "SSH2 protocol library" optional = false python-versions = ">=3.6" files = [ - {file = "paramiko-3.4.1-py3-none-any.whl", hash = "sha256:8e49fd2f82f84acf7ffd57c64311aa2b30e575370dc23bdb375b10262f7eac32"}, - {file = "paramiko-3.4.1.tar.gz", hash = "sha256:8b15302870af7f6652f2e038975c1d2973f06046cb5d7d65355668b3ecbece0c"}, + {file = "paramiko-3.5.0-py3-none-any.whl", hash = "sha256:1fedf06b085359051cd7d0d270cebe19e755a8a921cc2ddbfa647fb0cd7d68f9"}, + {file = "paramiko-3.5.0.tar.gz", hash = "sha256:ad11e540da4f55cedda52931f1a3f812a8238a7af7f62a60de538cd80bb28124"}, ] [package.dependencies] @@ -2175,30 +2213,30 @@ regex = ">=2022.3.15" [[package]] name = "pefile" -version = "2024.8.26" +version = "2023.2.7" description = "Python PE parsing module" optional = false python-versions = ">=3.6.0" files = [ - {file = "pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f"}, - {file = "pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632"}, + {file = "pefile-2023.2.7-py3-none-any.whl", hash = "sha256:da185cd2af68c08a6cd4481f7325ed600a88f6a813bad9dea07ab3ef73d8d8d6"}, + {file = "pefile-2023.2.7.tar.gz", hash = "sha256:82e6114004b3d6911c77c3953e3838654b04511b8b66e8583db70c65998017dc"}, ] [[package]] name = "platformdirs" -version = "4.2.2" +version = "4.3.6" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -2215,6 +2253,113 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "propcache" +version = "0.2.0" +description = "Accelerated property cache" +optional = false +python-versions = ">=3.8" +files = [ + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c5869b8fd70b81835a6f187c5fdbe67917a04d7e52b6e7cc4e5fe39d55c39d58"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:952e0d9d07609d9c5be361f33b0d6d650cd2bae393aabb11d9b719364521984b"}, + {file = "propcache-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33ac8f098df0585c0b53009f039dfd913b38c1d2edafed0cedcc0c32a05aa110"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97e48e8875e6c13909c800fa344cd54cc4b2b0db1d5f911f840458a500fde2c2"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:388f3217649d6d59292b722d940d4d2e1e6a7003259eb835724092a1cca0203a"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f571aea50ba5623c308aa146eb650eebf7dbe0fd8c5d946e28343cb3b5aad577"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"}, + {file = "propcache-0.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a3ebe9a75be7ab0b7da2464a77bb27febcb4fab46a34f9288f39d74833db7f61"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2f0d0f976985f85dfb5f3d685697ef769faa6b71993b46b295cdbbd6be8cc37"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a3dc1a4b165283bd865e8f8cb5f0c64c05001e0718ed06250d8cac9bec115b48"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:9e0f07b42d2a50c7dd2d8675d50f7343d998c64008f1da5fef888396b7f84630"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e63e3e1e0271f374ed489ff5ee73d4b6e7c60710e1f76af5f0e1a6117cd26394"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:56bb5c98f058a41bb58eead194b4db8c05b088c93d94d5161728515bd52b052b"}, + {file = "propcache-0.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7665f04d0c7f26ff8bb534e1c65068409bf4687aa2534faf7104d7182debb336"}, + {file = "propcache-0.2.0-cp310-cp310-win32.whl", hash = "sha256:7cf18abf9764746b9c8704774d8b06714bcb0a63641518a3a89c7f85cc02c2ad"}, + {file = "propcache-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:cfac69017ef97db2438efb854edf24f5a29fd09a536ff3a992b75990720cdc99"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de"}, + {file = "propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4"}, + {file = "propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b"}, + {file = "propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b"}, + {file = "propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1"}, + {file = "propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7"}, + {file = "propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e"}, + {file = "propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23"}, + {file = "propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348"}, + {file = "propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5"}, + {file = "propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763"}, + {file = "propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf"}, + {file = "propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83"}, + {file = "propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544"}, + {file = "propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032"}, + {file = "propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:53d1bd3f979ed529f0805dd35ddaca330f80a9a6d90bc0121d2ff398f8ed8861"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:83928404adf8fb3d26793665633ea79b7361efa0287dfbd372a7e74311d51ee6"}, + {file = "propcache-0.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:77a86c261679ea5f3896ec060be9dc8e365788248cc1e049632a1be682442063"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:218db2a3c297a3768c11a34812e63b3ac1c3234c3a086def9c0fee50d35add1f"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7735e82e3498c27bcb2d17cb65d62c14f1100b71723b68362872bca7d0913d90"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:20a617c776f520c3875cf4511e0d1db847a076d720714ae35ffe0df3e440be68"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67b69535c870670c9f9b14a75d28baa32221d06f6b6fa6f77a0a13c5a7b0a5b9"}, + {file = "propcache-0.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4569158070180c3855e9c0791c56be3ceeb192defa2cdf6a3f39e54319e56b89"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:db47514ffdbd91ccdc7e6f8407aac4ee94cc871b15b577c1c324236b013ddd04"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:2a60ad3e2553a74168d275a0ef35e8c0a965448ffbc3b300ab3a5bb9956c2162"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:662dd62358bdeaca0aee5761de8727cfd6861432e3bb828dc2a693aa0471a563"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:25a1f88b471b3bc911d18b935ecb7115dff3a192b6fef46f0bfaf71ff4f12418"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:f60f0ac7005b9f5a6091009b09a419ace1610e163fa5deaba5ce3484341840e7"}, + {file = "propcache-0.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:74acd6e291f885678631b7ebc85d2d4aec458dd849b8c841b57ef04047833bed"}, + {file = "propcache-0.2.0-cp38-cp38-win32.whl", hash = "sha256:d9b6ddac6408194e934002a69bcaadbc88c10b5f38fb9307779d1c629181815d"}, + {file = "propcache-0.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:676135dcf3262c9c5081cc8f19ad55c8a64e3f7282a21266d05544450bffc3a5"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:25c8d773a62ce0451b020c7b29a35cfbc05de8b291163a7a0f3b7904f27253e6"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:375a12d7556d462dc64d70475a9ee5982465fbb3d2b364f16b86ba9135793638"}, + {file = "propcache-0.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1ec43d76b9677637a89d6ab86e1fef70d739217fefa208c65352ecf0282be957"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f45eec587dafd4b2d41ac189c2156461ebd0c1082d2fe7013571598abb8505d1"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc092ba439d91df90aea38168e11f75c655880c12782facf5cf9c00f3d42b562"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fa1076244f54bb76e65e22cb6910365779d5c3d71d1f18b275f1dfc7b0d71b4d"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:682a7c79a2fbf40f5dbb1eb6bfe2cd865376deeac65acf9beb607505dced9e12"}, + {file = "propcache-0.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e40876731f99b6f3c897b66b803c9e1c07a989b366c6b5b475fafd1f7ba3fb8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:363ea8cd3c5cb6679f1c2f5f1f9669587361c062e4899fce56758efa928728f8"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:140fbf08ab3588b3468932974a9331aff43c0ab8a2ec2c608b6d7d1756dbb6cb"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e70fac33e8b4ac63dfc4c956fd7d85a0b1139adcfc0d964ce288b7c527537fea"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:b33d7a286c0dc1a15f5fc864cc48ae92a846df287ceac2dd499926c3801054a6"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f6d5749fdd33d90e34c2efb174c7e236829147a2713334d708746e94c4bde40d"}, + {file = "propcache-0.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:22aa8f2272d81d9317ff5756bb108021a056805ce63dd3630e27d042c8092798"}, + {file = "propcache-0.2.0-cp39-cp39-win32.whl", hash = "sha256:73e4b40ea0eda421b115248d7e79b59214411109a5bc47d0d48e4c73e3b8fcf9"}, + {file = "propcache-0.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:9517d5e9e0731957468c29dbfd0f976736a0e55afaea843726e887f36fe017df"}, + {file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"}, + {file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"}, +] + [[package]] name = "protobuf" version = "4.24.4" @@ -2321,160 +2466,172 @@ files = [ [[package]] name = "pycryptodome" -version = "3.20.0" +version = "3.21.0" description = "Cryptographic library for Python" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "pycryptodome-3.20.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:f0e6d631bae3f231d3634f91ae4da7a960f7ff87f2865b2d2b831af1dfb04e9a"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:baee115a9ba6c5d2709a1e88ffe62b73ecc044852a925dcb67713a288c4ec70f"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:417a276aaa9cb3be91f9014e9d18d10e840a7a9b9a9be64a42f553c5b50b4d1d"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a1250b7ea809f752b68e3e6f3fd946b5939a52eaeea18c73bdab53e9ba3c2dd"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:d5954acfe9e00bc83ed9f5cb082ed22c592fbbef86dc48b907238be64ead5c33"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-win32.whl", hash = "sha256:06d6de87c19f967f03b4cf9b34e538ef46e99a337e9a61a77dbe44b2cbcf0690"}, - {file = "pycryptodome-3.20.0-cp27-cp27m-win_amd64.whl", hash = "sha256:ec0bb1188c1d13426039af8ffcb4dbe3aad1d7680c35a62d8eaf2a529b5d3d4f"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5601c934c498cd267640b57569e73793cb9a83506f7c73a8ec57a516f5b0b091"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d29daa681517f4bc318cd8a23af87e1f2a7bad2fe361e8aa29c77d652a065de4"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3427d9e5310af6680678f4cce149f54e0bb4af60101c7f2c16fdf878b39ccccc"}, - {file = "pycryptodome-3.20.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:3cd3ef3aee1079ae44afaeee13393cf68b1058f70576b11439483e34f93cf818"}, - {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac1c7c0624a862f2e53438a15c9259d1655325fc2ec4392e66dc46cdae24d044"}, - {file = "pycryptodome-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:76658f0d942051d12a9bd08ca1b6b34fd762a8ee4240984f7c06ddfb55eaf15a"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f35d6cee81fa145333137009d9c8ba90951d7d77b67c79cbe5f03c7eb74d8fe2"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cb39afede7055127e35a444c1c041d2e8d2f1f9c121ecef573757ba4cd2c3c"}, - {file = "pycryptodome-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49a4c4dc60b78ec41d2afa392491d788c2e06edf48580fbfb0dd0f828af49d25"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:fb3b87461fa35afa19c971b0a2b7456a7b1db7b4eba9a8424666104925b78128"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:acc2614e2e5346a4a4eab6e199203034924313626f9620b7b4b38e9ad74b7e0c"}, - {file = "pycryptodome-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:210ba1b647837bfc42dd5a813cdecb5b86193ae11a3f5d972b9a0ae2c7e9e4b4"}, - {file = "pycryptodome-3.20.0-cp35-abi3-win32.whl", hash = "sha256:8d6b98d0d83d21fb757a182d52940d028564efe8147baa9ce0f38d057104ae72"}, - {file = "pycryptodome-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:9b3ae153c89a480a0ec402e23db8d8d84a3833b65fa4b15b81b83be9d637aab9"}, - {file = "pycryptodome-3.20.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:4401564ebf37dfde45d096974c7a159b52eeabd9969135f0426907db367a652a"}, - {file = "pycryptodome-3.20.0-pp27-pypy_73-win32.whl", hash = "sha256:ec1f93feb3bb93380ab0ebf8b859e8e5678c0f010d2d78367cf6bc30bfeb148e"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:acae12b9ede49f38eb0ef76fdec2df2e94aad85ae46ec85be3648a57f0a7db04"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f47888542a0633baff535a04726948e876bf1ed880fddb7c10a736fa99146ab3"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e0e4a987d38cfc2e71b4a1b591bae4891eeabe5fa0f56154f576e26287bfdea"}, - {file = "pycryptodome-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c18b381553638414b38705f07d1ef0a7cf301bc78a5f9bc17a957eb19446834b"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a60fedd2b37b4cb11ccb5d0399efe26db9e0dd149016c1cc6c8161974ceac2d6"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:405002eafad114a2f9a930f5db65feef7b53c4784495dd8758069b89baf68eab"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ab6ab0cb755154ad14e507d1df72de9897e99fd2d4922851a276ccc14f4f1a5"}, - {file = "pycryptodome-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acf6e43fa75aca2d33e93409f2dafe386fe051818ee79ee8a3e21de9caa2ac9e"}, - {file = "pycryptodome-3.20.0.tar.gz", hash = "sha256:09609209ed7de61c2b560cc5c8c4fbf892f8b15b1faf7e4cbffac97db1fffda7"}, +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +files = [ + {file = "pycryptodome-3.21.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:dad9bf36eda068e89059d1f07408e397856be9511d7113ea4b586642a429a4fd"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:a1752eca64c60852f38bb29e2c86fca30d7672c024128ef5d70cc15868fa10f4"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ba4cc304eac4d4d458f508d4955a88ba25026890e8abff9b60404f76a62c55e"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cb087b8612c8a1a14cf37dd754685be9a8d9869bed2ffaaceb04850a8aeef7e"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-musllinux_1_1_aarch64.whl", hash = "sha256:26412b21df30b2861424a6c6d5b1d8ca8107612a4cfa4d0183e71c5d200fb34a"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-win32.whl", hash = "sha256:cc2269ab4bce40b027b49663d61d816903a4bd90ad88cb99ed561aadb3888dd3"}, + {file = "pycryptodome-3.21.0-cp27-cp27m-win_amd64.whl", hash = "sha256:0fa0a05a6a697ccbf2a12cec3d6d2650b50881899b845fac6e87416f8cb7e87d"}, + {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6cce52e196a5f1d6797ff7946cdff2038d3b5f0aba4a43cb6bf46b575fd1b5bb"}, + {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a915597ffccabe902e7090e199a7bf7a381c5506a747d5e9d27ba55197a2c568"}, + {file = "pycryptodome-3.21.0-cp27-cp27mu-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4e74c522d630766b03a836c15bff77cb657c5fdf098abf8b1ada2aebc7d0819"}, + {file = "pycryptodome-3.21.0-cp27-cp27mu-musllinux_1_1_aarch64.whl", hash = "sha256:a3804675283f4764a02db05f5191eb8fec2bb6ca34d466167fc78a5f05bbe6b3"}, + {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4"}, + {file = "pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b"}, + {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e"}, + {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8"}, + {file = "pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1"}, + {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a"}, + {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2"}, + {file = "pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93"}, + {file = "pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764"}, + {file = "pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53"}, + {file = "pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca"}, + {file = "pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd"}, + {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8"}, + {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6"}, + {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0"}, + {file = "pycryptodome-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6"}, + {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:590ef0898a4b0a15485b05210b4a1c9de8806d3ad3d47f74ab1dc07c67a6827f"}, + {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f35e442630bc4bc2e1878482d6f59ea22e280d7121d7adeaedba58c23ab6386b"}, + {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff99f952db3db2fbe98a0b355175f93ec334ba3d01bbde25ad3a5a33abc02b58"}, + {file = "pycryptodome-3.21.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8acd7d34af70ee63f9a849f957558e49a98f8f1634f86a59d2be62bb8e93f71c"}, + {file = "pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297"}, ] [[package]] name = "pydantic" -version = "2.8.2" +version = "2.10.0" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8"}, - {file = "pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a"}, + {file = "pydantic-2.10.0-py3-none-any.whl", hash = "sha256:5e7807ba9201bdf61b1b58aa6eb690916c40a47acfb114b1b4fef3e7fd5b30fc"}, + {file = "pydantic-2.10.0.tar.gz", hash = "sha256:0aca0f045ff6e2f097f1fe89521115335f15049eeb8a7bef3dafe4b19a74e289"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.20.1" -typing-extensions = {version = ">=4.6.1", markers = "python_version < \"3.13\""} +annotated-types = ">=0.6.0" +pydantic-core = "2.27.0" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.20.1" +version = "2.27.0" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98"}, - {file = "pydantic_core-2.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a"}, - {file = "pydantic_core-2.20.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840"}, - {file = "pydantic_core-2.20.1-cp310-none-win32.whl", hash = "sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250"}, - {file = "pydantic_core-2.20.1-cp310-none-win_amd64.whl", hash = "sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312"}, - {file = "pydantic_core-2.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1"}, - {file = "pydantic_core-2.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27"}, - {file = "pydantic_core-2.20.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b"}, - {file = "pydantic_core-2.20.1-cp311-none-win32.whl", hash = "sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a"}, - {file = "pydantic_core-2.20.1-cp311-none-win_amd64.whl", hash = "sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231"}, - {file = "pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e"}, - {file = "pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1"}, - {file = "pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd"}, - {file = "pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688"}, - {file = "pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686"}, - {file = "pydantic_core-2.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c"}, - {file = "pydantic_core-2.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203"}, - {file = "pydantic_core-2.20.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0"}, - {file = "pydantic_core-2.20.1-cp313-none-win32.whl", hash = "sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e"}, - {file = "pydantic_core-2.20.1-cp313-none-win_amd64.whl", hash = "sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:4745f4ac52cc6686390c40eaa01d48b18997cb130833154801a442323cc78f91"}, - {file = "pydantic_core-2.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a8ad4c766d3f33ba8fd692f9aa297c9058970530a32c728a2c4bfd2616d3358b"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41e81317dd6a0127cabce83c0c9c3fbecceae981c8391e6f1dec88a77c8a569a"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04024d270cf63f586ad41fff13fde4311c4fc13ea74676962c876d9577bcc78f"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eaad4ff2de1c3823fddf82f41121bdf453d922e9a238642b1dedb33c4e4f98ad"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:26ab812fa0c845df815e506be30337e2df27e88399b985d0bb4e3ecfe72df31c"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c5ebac750d9d5f2706654c638c041635c385596caf68f81342011ddfa1e5598"}, - {file = "pydantic_core-2.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2aafc5a503855ea5885559eae883978c9b6d8c8993d67766ee73d82e841300dd"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4868f6bd7c9d98904b748a2653031fc9c2f85b6237009d475b1008bfaeb0a5aa"}, - {file = "pydantic_core-2.20.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa2f457b4af386254372dfa78a2eda2563680d982422641a85f271c859df1987"}, - {file = "pydantic_core-2.20.1-cp38-none-win32.whl", hash = "sha256:225b67a1f6d602de0ce7f6c1c3ae89a4aa25d3de9be857999e9124f15dab486a"}, - {file = "pydantic_core-2.20.1-cp38-none-win_amd64.whl", hash = "sha256:6b507132dcfc0dea440cce23ee2182c0ce7aba7054576efc65634f080dbe9434"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b03f7941783b4c4a26051846dea594628b38f6940a2fdc0df00b221aed39314c"}, - {file = "pydantic_core-2.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1eedfeb6089ed3fad42e81a67755846ad4dcc14d73698c120a82e4ccf0f1f9f6"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:635fee4e041ab9c479e31edda27fcf966ea9614fff1317e280d99eb3e5ab6fe2"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:77bf3ac639c1ff567ae3b47f8d4cc3dc20f9966a2a6dd2311dcc055d3d04fb8a"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ed1b0132f24beeec5a78b67d9388656d03e6a7c837394f99257e2d55b461611"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6514f963b023aeee506678a1cf821fe31159b925c4b76fe2afa94cc70b3222b"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10d4204d8ca33146e761c79f83cc861df20e7ae9f6487ca290a97702daf56006"}, - {file = "pydantic_core-2.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d036c7187b9422ae5b262badb87a20a49eb6c5238b2004e96d4da1231badef1"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9ebfef07dbe1d93efb94b4700f2d278494e9162565a54f124c404a5656d7ff09"}, - {file = "pydantic_core-2.20.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6b9d9bb600328a1ce523ab4f454859e9d439150abb0906c5a1983c146580ebab"}, - {file = "pydantic_core-2.20.1-cp39-none-win32.whl", hash = "sha256:784c1214cb6dd1e3b15dd8b91b9a53852aed16671cc3fbe4786f4f1db07089e2"}, - {file = "pydantic_core-2.20.1-cp39-none-win_amd64.whl", hash = "sha256:d2fe69c5434391727efa54b47a1e7986bb0186e72a41b203df8f5b0a19a4f669"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99"}, - {file = "pydantic_core-2.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:407653af5617f0757261ae249d3fba09504d7a71ab36ac057c938572d1bc9331"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c693e916709c2465b02ca0ad7b387c4f8423d1db7b4649c551f27a529181c5ad"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b5ff4911aea936a47d9376fd3ab17e970cc543d1b68921886e7f64bd28308d1"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f55a886d74f1808763976ac4efd29b7ed15c69f4d838bbd74d9d09cf6fa86"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:964faa8a861d2664f0c7ab0c181af0bea66098b1919439815ca8803ef136fc4e"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4dd484681c15e6b9a977c785a345d3e378d72678fd5f1f3c0509608da24f2ac0"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f6d6cff3538391e8486a431569b77921adfcdef14eb18fbf19b7c0a5294d4e6a"}, - {file = "pydantic_core-2.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a6d511cc297ff0883bc3708b465ff82d7560193169a8b93260f74ecb0a5e08a7"}, - {file = "pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4"}, + {file = "pydantic_core-2.27.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2ac6b919f7fed71b17fe0b4603c092a4c9b5bae414817c9c81d3c22d1e1bcc"}, + {file = "pydantic_core-2.27.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e015833384ca3e1a0565a79f5d953b0629d9138021c27ad37c92a9fa1af7623c"}, + {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db72e40628967f6dc572020d04b5f800d71264e0531c6da35097e73bdf38b003"}, + {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df45c4073bed486ea2f18757057953afed8dd77add7276ff01bccb79982cf46c"}, + {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:836a4bfe0cc6d36dc9a9cc1a7b391265bf6ce9d1eb1eac62ac5139f5d8d9a6fa"}, + {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4bf1340ae507f6da6360b24179c2083857c8ca7644aab65807023cf35404ea8d"}, + {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ab325fc86fbc077284c8d7f996d904d30e97904a87d6fb303dce6b3de7ebba9"}, + {file = "pydantic_core-2.27.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1da0c98a85a6c6ed702d5556db3b09c91f9b0b78de37b7593e2de8d03238807a"}, + {file = "pydantic_core-2.27.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:7b0202ebf2268954090209a84f9897345719e46a57c5f2c9b7b250ca0a9d3e63"}, + {file = "pydantic_core-2.27.0-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:35380671c3c921fe8adf31ad349dc6f7588b7e928dbe44e1093789734f607399"}, + {file = "pydantic_core-2.27.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b4c19525c3538fbc0bbda6229f9682fb8199ce9ac37395880e6952798e00373"}, + {file = "pydantic_core-2.27.0-cp310-none-win32.whl", hash = "sha256:333c840a1303d1474f491e7be0b718226c730a39ead0f7dab2c7e6a2f3855555"}, + {file = "pydantic_core-2.27.0-cp310-none-win_amd64.whl", hash = "sha256:99b2863c1365f43f74199c980a3d40f18a218fbe683dd64e470199db426c4d6a"}, + {file = "pydantic_core-2.27.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4523c4009c3f39d948e01962223c9f5538602e7087a628479b723c939fab262d"}, + {file = "pydantic_core-2.27.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:84af1cf7bfdcbc6fcf5a5f70cc9896205e0350306e4dd73d54b6a18894f79386"}, + {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e65466b31be1070b4a5b7dbfbd14b247884cb8e8b79c64fb0f36b472912dbaea"}, + {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a5c022bb0d453192426221605efc865373dde43b17822a264671c53b068ac20c"}, + {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6bb69bf3b6500f195c3deb69c1205ba8fc3cb21d1915f1f158a10d6b1ef29b6a"}, + {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0aa4d1b2eba9a325897308b3124014a142cdccb9f3e016f31d3ebee6b5ea5e75"}, + {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e96ca781e0c01e32115912ebdf7b3fb0780ce748b80d7d28a0802fa9fbaf44e"}, + {file = "pydantic_core-2.27.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b872c86d8d71827235c7077461c502feb2db3f87d9d6d5a9daa64287d75e4fa0"}, + {file = "pydantic_core-2.27.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:82e1ad4ca170e8af4c928b67cff731b6296e6a0a0981b97b2eb7c275cc4e15bd"}, + {file = "pydantic_core-2.27.0-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:eb40f828bc2f73f777d1eb8fee2e86cd9692a4518b63b6b5aa8af915dfd3207b"}, + {file = "pydantic_core-2.27.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9a8fbf506fde1529a1e3698198fe64bfbe2e0c09557bc6a7dcf872e7c01fec40"}, + {file = "pydantic_core-2.27.0-cp311-none-win32.whl", hash = "sha256:24f984fc7762ed5f806d9e8c4c77ea69fdb2afd987b4fd319ef06c87595a8c55"}, + {file = "pydantic_core-2.27.0-cp311-none-win_amd64.whl", hash = "sha256:68950bc08f9735306322bfc16a18391fcaac99ded2509e1cc41d03ccb6013cfe"}, + {file = "pydantic_core-2.27.0-cp311-none-win_arm64.whl", hash = "sha256:3eb8849445c26b41c5a474061032c53e14fe92a11a5db969f722a2716cd12206"}, + {file = "pydantic_core-2.27.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8117839a9bdbba86e7f9df57018fe3b96cec934c3940b591b0fd3fbfb485864a"}, + {file = "pydantic_core-2.27.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a291d0b4243a259c8ea7e2b84eb9ccb76370e569298875a7c5e3e71baf49057a"}, + {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84e35afd9e10b2698e6f2f32256678cb23ca6c1568d02628033a837638b3ed12"}, + {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:58ab0d979c969983cdb97374698d847a4acffb217d543e172838864636ef10d9"}, + {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d06b667e53320332be2bf6f9461f4a9b78092a079b8ce8634c9afaa7e10cd9f"}, + {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78f841523729e43e3928a364ec46e2e3f80e6625a4f62aca5c345f3f626c6e8a"}, + {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:400bf470e4327e920883b51e255617dfe4496d4e80c3fea0b5a5d0bf2c404dd4"}, + {file = "pydantic_core-2.27.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:951e71da6c89d354572098bada5ba5b5dc3a9390c933af8a614e37755d3d1840"}, + {file = "pydantic_core-2.27.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:2a51ce96224eadd1845150b204389623c8e129fde5a67a84b972bd83a85c6c40"}, + {file = "pydantic_core-2.27.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:483c2213a609e7db2c592bbc015da58b6c75af7360ca3c981f178110d9787bcf"}, + {file = "pydantic_core-2.27.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:359e7951f04ad35111b5ddce184db3391442345d0ab073aa63a95eb8af25a5ef"}, + {file = "pydantic_core-2.27.0-cp312-none-win32.whl", hash = "sha256:ee7d9d5537daf6d5c74a83b38a638cc001b648096c1cae8ef695b0c919d9d379"}, + {file = "pydantic_core-2.27.0-cp312-none-win_amd64.whl", hash = "sha256:2be0ad541bb9f059954ccf8877a49ed73877f862529575ff3d54bf4223e4dd61"}, + {file = "pydantic_core-2.27.0-cp312-none-win_arm64.whl", hash = "sha256:6e19401742ed7b69e51d8e4df3c03ad5ec65a83b36244479fd70edde2828a5d9"}, + {file = "pydantic_core-2.27.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5f2b19b8d6fca432cb3acf48cf5243a7bf512988029b6e6fd27e9e8c0a204d85"}, + {file = "pydantic_core-2.27.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c86679f443e7085ea55a7376462553996c688395d18ef3f0d3dbad7838f857a2"}, + {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:510b11e9c3b1a852876d1ccd8d5903684336d635214148637ceb27366c75a467"}, + {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb704155e73b833801c247f39d562229c0303f54770ca14fb1c053acb376cf10"}, + {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ce048deb1e033e7a865ca384770bccc11d44179cf09e5193a535c4c2f497bdc"}, + {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58560828ee0951bb125c6f2862fbc37f039996d19ceb6d8ff1905abf7da0bf3d"}, + {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb4785894936d7682635726613c44578c420a096729f1978cd061a7e72d5275"}, + {file = "pydantic_core-2.27.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2883b260f7a93235488699d39cbbd94fa7b175d3a8063fbfddd3e81ad9988cb2"}, + {file = "pydantic_core-2.27.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c6fcb3fa3855d583aa57b94cf146f7781d5d5bc06cb95cb3afece33d31aac39b"}, + {file = "pydantic_core-2.27.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:e851a051f7260e6d688267eb039c81f05f23a19431bd7dfa4bf5e3cb34c108cd"}, + {file = "pydantic_core-2.27.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edb1bfd45227dec8d50bc7c7d86463cd8728bcc574f9b07de7369880de4626a3"}, + {file = "pydantic_core-2.27.0-cp313-none-win32.whl", hash = "sha256:678f66462058dd978702db17eb6a3633d634f7aa0deaea61e0a674152766d3fc"}, + {file = "pydantic_core-2.27.0-cp313-none-win_amd64.whl", hash = "sha256:d28ca7066d6cdd347a50d8b725dc10d9a1d6a1cce09836cf071ea6a2d4908be0"}, + {file = "pydantic_core-2.27.0-cp313-none-win_arm64.whl", hash = "sha256:6f4a53af9e81d757756508b57cae1cf28293f0f31b9fa2bfcb416cc7fb230f9d"}, + {file = "pydantic_core-2.27.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:e9f9feee7f334b72ceae46313333d002b56f325b5f04271b4ae2aadd9e993ae4"}, + {file = "pydantic_core-2.27.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:225bfff5d425c34e1fd562cef52d673579d59b967d9de06178850c4802af9039"}, + {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921ad596ff1a82f9c692b0758c944355abc9f0de97a4c13ca60ffc6d8dc15d4"}, + {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6354e18a9be37bfa124d6b288a87fb30c673745806c92956f1a25e3ae6e76b96"}, + {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ee4c2a75af9fe21269a4a0898c5425afb01af1f5d276063f57e2ae1bc64e191"}, + {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c91e3c04f5191fd3fb68764bddeaf02025492d5d9f23343b283870f6ace69708"}, + {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a6ebfac28fd51890a61df36ef202adbd77d00ee5aca4a3dadb3d9ed49cfb929"}, + {file = "pydantic_core-2.27.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36aa167f69d8807ba7e341d67ea93e50fcaaf6bc433bb04939430fa3dab06f31"}, + {file = "pydantic_core-2.27.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e8d89c276234579cd3d095d5fa2a44eb10db9a218664a17b56363cddf226ff3"}, + {file = "pydantic_core-2.27.0-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:5cc822ab90a70ea3a91e6aed3afac570b276b1278c6909b1d384f745bd09c714"}, + {file = "pydantic_core-2.27.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e15315691fe2253eb447503153acef4d7223dfe7e7702f9ed66539fcd0c43801"}, + {file = "pydantic_core-2.27.0-cp38-none-win32.whl", hash = "sha256:dfa5f5c0a4c8fced1422dc2ca7eefd872d5d13eb33cf324361dbf1dbfba0a9fe"}, + {file = "pydantic_core-2.27.0-cp38-none-win_amd64.whl", hash = "sha256:513cb14c0cc31a4dfd849a4674b20c46d87b364f997bbcb02282306f5e187abf"}, + {file = "pydantic_core-2.27.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:4148dc9184ab79e356dc00a4199dc0ee8647973332cb385fc29a7cced49b9f9c"}, + {file = "pydantic_core-2.27.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5fc72fbfebbf42c0856a824b8b0dc2b5cd2e4a896050281a21cfa6fed8879cb1"}, + {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:185ef205256cd8b38431205698531026979db89a79587725c1e55c59101d64e9"}, + {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:395e3e1148fa7809016231f8065f30bb0dc285a97b4dc4360cd86e17bab58af7"}, + {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33d14369739c5d07e2e7102cdb0081a1fa46ed03215e07f097b34e020b83b1ae"}, + {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7820bb0d65e3ce1e3e70b6708c2f66143f55912fa02f4b618d0f08b61575f12"}, + {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43b61989068de9ce62296cde02beffabcadb65672207fc51e7af76dca75e6636"}, + {file = "pydantic_core-2.27.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15e350efb67b855cd014c218716feea4986a149ed1f42a539edd271ee074a196"}, + {file = "pydantic_core-2.27.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:433689845288f9a1ee5714444e65957be26d30915f7745091ede4a83cfb2d7bb"}, + {file = "pydantic_core-2.27.0-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:3fd8bc2690e7c39eecdf9071b6a889ce7b22b72073863940edc2a0a23750ca90"}, + {file = "pydantic_core-2.27.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:884f1806609c2c66564082540cffc96868c5571c7c3cf3a783f63f2fb49bd3cd"}, + {file = "pydantic_core-2.27.0-cp39-none-win32.whl", hash = "sha256:bf37b72834e7239cf84d4a0b2c050e7f9e48bced97bad9bdf98d26b8eb72e846"}, + {file = "pydantic_core-2.27.0-cp39-none-win_amd64.whl", hash = "sha256:31a2cae5f059329f9cfe3d8d266d3da1543b60b60130d186d9b6a3c20a346361"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:4fb49cfdb53af5041aba909be00cccfb2c0d0a2e09281bf542371c5fd36ad04c"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:49633583eb7dc5cba61aaf7cdb2e9e662323ad394e543ee77af265736bcd3eaa"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:153017e3d6cd3ce979de06d84343ca424bb6092727375eba1968c8b4693c6ecb"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff63a92f6e249514ef35bc795de10745be0226eaea06eb48b4bbeaa0c8850a4a"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5982048129f40b082c2654de10c0f37c67a14f5ff9d37cf35be028ae982f26df"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:91bc66f878557313c2a6bcf396e7befcffe5ab4354cfe4427318968af31143c3"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:68ef5377eb582fa4343c9d0b57a5b094046d447b4c73dd9fbd9ffb216f829e7d"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c5726eec789ee38f2c53b10b1821457b82274f81f4f746bb1e666d8741fcfadb"}, + {file = "pydantic_core-2.27.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c0c431e4be5c1a0c6654e0c31c661cd89e0ca956ef65305c3c3fd96f4e72ca39"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8e21d927469d04b39386255bf00d0feedead16f6253dcc85e9e10ddebc334084"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4b51f964fcbb02949fc546022e56cdb16cda457af485e9a3e8b78ac2ecf5d77e"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a7fd4de38f7ff99a37e18fa0098c3140286451bc823d1746ba80cec5b433a1"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fda87808429c520a002a85d6e7cdadbf58231d60e96260976c5b8f9a12a8e13"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8a150392102c402c538190730fda06f3bce654fc498865579a9f2c1d2b425833"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c9ed88b398ba7e3bad7bd64d66cc01dcde9cfcb7ec629a6fd78a82fa0b559d78"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:9fe94d9d2a2b4edd7a4b22adcd45814b1b59b03feb00e56deb2e89747aec7bfe"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d8b5ee4ae9170e2775d495b81f414cc20268041c42571530513496ba61e94ba3"}, + {file = "pydantic_core-2.27.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d29e235ce13c91902ef3efc3d883a677655b3908b1cbc73dee816e5e1f8f7739"}, + {file = "pydantic_core-2.27.0.tar.gz", hash = "sha256:f57783fbaf648205ac50ae7d646f27582fc706be3977e87c3c124e7a92407b10"}, ] [package.dependencies] @@ -2482,23 +2639,23 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pyinstaller" -version = "6.10.0" +version = "6.11.1" description = "PyInstaller bundles a Python application and all its dependencies into a single package." optional = false python-versions = "<3.14,>=3.8" files = [ - {file = "pyinstaller-6.10.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:d60fb22859e11483af735aec115fdde09467cdbb29edd9844839f2c920b748c0"}, - {file = "pyinstaller-6.10.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:46d75359668993ddd98630a3669dc5249f3c446e35239b43bc7f4155bc574748"}, - {file = "pyinstaller-6.10.0-py3-none-manylinux2014_i686.whl", hash = "sha256:3398a98fa17d47ccb31f8779ecbdacec025f7adb2f22757a54b706ac8b4fe906"}, - {file = "pyinstaller-6.10.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e9989f354ae4ed8a3bec7bdb37ae0d170751d6520e500f049c7cd0632d31d5c3"}, - {file = "pyinstaller-6.10.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:b7c90c91921b3749083115b28f30f40abf2bb481ceff196d2b2ce0eaa2b3d429"}, - {file = "pyinstaller-6.10.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6cf876d7d93b8b4f28d1ad57fa24645cf43119c79e985dd5e5f7a801245e6f53"}, - {file = "pyinstaller-6.10.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:db05e3f2f10f9f78c56f1fb163d9cb453433429fe4281218ebaf1ebfd39ba942"}, - {file = "pyinstaller-6.10.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:28eca3817f176fdc19747e1afcf434f13bb9f17a644f611be2c5a61b1f498ed7"}, - {file = "pyinstaller-6.10.0-py3-none-win32.whl", hash = "sha256:703e041718987e46ba0568a2c71ecf2459fddef57cf9edf3efeed4a53e3dae3f"}, - {file = "pyinstaller-6.10.0-py3-none-win_amd64.whl", hash = "sha256:95b55966e563e8b8f31a43882aea10169e9a11fdf38e626d86a2907b640c0701"}, - {file = "pyinstaller-6.10.0-py3-none-win_arm64.whl", hash = "sha256:308e0a8670c9c9ac0cebbf1bbb492e71b6675606f2ec78bc4adfc830d209e087"}, - {file = "pyinstaller-6.10.0.tar.gz", hash = "sha256:143840f8056ff7b910bf8f16f6cd92cc10a6c2680bb76d0a25d558d543d21270"}, + {file = "pyinstaller-6.11.1-py3-none-macosx_10_13_universal2.whl", hash = "sha256:44e36172de326af6d4e7663b12f71dbd34e2e3e02233e181e457394423daaf03"}, + {file = "pyinstaller-6.11.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:6d12c45a29add78039066a53fb05967afaa09a672426072b13816fe7676abfc4"}, + {file = "pyinstaller-6.11.1-py3-none-manylinux2014_i686.whl", hash = "sha256:ddc0fddd75f07f7e423da1f0822e389a42af011f9589e0269b87e0d89aa48c1f"}, + {file = "pyinstaller-6.11.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:0d6475559c4939f0735122989611d7f739ed3bf02f666ce31022928f7a7e4fda"}, + {file = "pyinstaller-6.11.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:e21c7806e34f40181e7606926a14579f848bfb1dc52cbca7eea66eccccbfe977"}, + {file = "pyinstaller-6.11.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:32c742a24fe65d0702958fadf4040f76de85859c26bec0008766e5dbabc5b68f"}, + {file = "pyinstaller-6.11.1-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:208c0ef6dab0837a0a273ea32d1a3619a208e3d1fe3fec3785eea71a77fd00ce"}, + {file = "pyinstaller-6.11.1-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:ad84abf465bcda363c1d54eafa76745d77b6a8a713778348377dc98d12a452f7"}, + {file = "pyinstaller-6.11.1-py3-none-win32.whl", hash = "sha256:2e8365276c5131c9bef98e358fbc305e4022db8bedc9df479629d6414021956a"}, + {file = "pyinstaller-6.11.1-py3-none-win_amd64.whl", hash = "sha256:7ac83c0dc0e04357dab98c487e74ad2adb30e7eb186b58157a8faf46f1fa796f"}, + {file = "pyinstaller-6.11.1-py3-none-win_arm64.whl", hash = "sha256:35e6b8077d240600bb309ed68bb0b1453fd2b7ab740b66d000db7abae6244423"}, + {file = "pyinstaller-6.11.1.tar.gz", hash = "sha256:491dfb4d9d5d1d9650d9507daec1ff6829527a254d8e396badd60a0affcb72ef"}, ] [package.dependencies] @@ -2506,8 +2663,8 @@ altgraph = "*" importlib-metadata = {version = ">=4.6", markers = "python_version < \"3.10\""} macholib = {version = ">=1.8", markers = "sys_platform == \"darwin\""} packaging = ">=22.0" -pefile = {version = ">=2022.5.30", markers = "sys_platform == \"win32\""} -pyinstaller-hooks-contrib = ">=2024.8" +pefile = {version = ">=2022.5.30,<2024.8.26 || >2024.8.26", markers = "sys_platform == \"win32\""} +pyinstaller-hooks-contrib = ">=2024.9" pywin32-ctypes = {version = ">=0.2.1", markers = "sys_platform == \"win32\""} setuptools = ">=42.0.0" @@ -2517,13 +2674,13 @@ hook-testing = ["execnet (>=1.5.0)", "psutil", "pytest (>=2.7.3)"] [[package]] name = "pyinstaller-hooks-contrib" -version = "2024.8" +version = "2024.10" description = "Community maintained hooks for PyInstaller" optional = false python-versions = ">=3.8" files = [ - {file = "pyinstaller_hooks_contrib-2024.8-py3-none-any.whl", hash = "sha256:0057fe9a5c398d3f580e73e58793a1d4a8315ca91c3df01efea1c14ed557825a"}, - {file = "pyinstaller_hooks_contrib-2024.8.tar.gz", hash = "sha256:29b68d878ab739e967055b56a93eb9b58e529d5b054fbab7a2f2bacf80cef3e2"}, + {file = "pyinstaller_hooks_contrib-2024.10-py3-none-any.whl", hash = "sha256:ad47db0e153683b4151e10d231cb91f2d93c85079e78d76d9e0f57ac6c8a5e10"}, + {file = "pyinstaller_hooks_contrib-2024.10.tar.gz", hash = "sha256:8a46655e5c5b0186b5e527399118a9b342f10513eb1425c483fa4f6d02e8800c"}, ] [package.dependencies] @@ -2676,25 +2833,29 @@ cli = ["click (>=5.0)"] [[package]] name = "pywin32" -version = "306" +version = "308" description = "Python for Window Extensions" optional = false python-versions = "*" files = [ - {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, - {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, - {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, - {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, - {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, - {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, - {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, - {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, - {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, - {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, - {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, - {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, - {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, - {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, + {file = "pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e"}, + {file = "pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e"}, + {file = "pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c"}, + {file = "pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a"}, + {file = "pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b"}, + {file = "pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6"}, + {file = "pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897"}, + {file = "pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47"}, + {file = "pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091"}, + {file = "pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed"}, + {file = "pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4"}, + {file = "pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd"}, + {file = "pywin32-308-cp37-cp37m-win32.whl", hash = "sha256:1f696ab352a2ddd63bd07430080dd598e6369152ea13a25ebcdd2f503a38f1ff"}, + {file = "pywin32-308-cp37-cp37m-win_amd64.whl", hash = "sha256:13dcb914ed4347019fbec6697a01a0aec61019c1046c2b905410d197856326a6"}, + {file = "pywin32-308-cp38-cp38-win32.whl", hash = "sha256:5794e764ebcabf4ff08c555b31bd348c9025929371763b2183172ff4708152f0"}, + {file = "pywin32-308-cp38-cp38-win_amd64.whl", hash = "sha256:3b92622e29d651c6b783e368ba7d6722b1634b8e70bd376fd7610fe1992e19de"}, + {file = "pywin32-308-cp39-cp39-win32.whl", hash = "sha256:7873ca4dc60ab3287919881a7d4f88baee4a6e639aa6962de25a98ba6b193341"}, + {file = "pywin32-308-cp39-cp39-win_amd64.whl", hash = "sha256:71b3322d949b4cc20776436a9c9ba0eeedcbc9c650daa536df63f0ff111bb920"}, ] [[package]] @@ -2770,90 +2931,105 @@ files = [ [[package]] name = "regex" -version = "2024.7.24" +version = "2024.11.6" description = "Alternative regular expression module, to replace re." optional = false python-versions = ">=3.8" files = [ - {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b0d3f567fafa0633aee87f08b9276c7062da9616931382993c03808bb68ce"}, - {file = "regex-2024.7.24-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3426de3b91d1bc73249042742f45c2148803c111d1175b283270177fdf669024"}, - {file = "regex-2024.7.24-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f273674b445bcb6e4409bf8d1be67bc4b58e8b46fd0d560055d515b8830063cd"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23acc72f0f4e1a9e6e9843d6328177ae3074b4182167e34119ec7233dfeccf53"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fd3d2e228cae024c411c5ccdffae4c315271eee4a8b839291f84f796b34eca"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c414cbda77dbf13c3bc88b073a1a9f375c7b0cb5e115e15d4b73ec3a2fbc6f59"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf7a89eef64b5455835f5ed30254ec19bf41f7541cd94f266ab7cbd463f00c41"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c65b00d42804e3fbea9708f0937d157e53429a39b7c61253ff15670ff62cb5"}, - {file = "regex-2024.7.24-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7a5486ca56c8869070a966321d5ab416ff0f83f30e0e2da1ab48815c8d165d46"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6f51f9556785e5a203713f5efd9c085b4a45aecd2a42573e2b5041881b588d1f"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a4997716674d36a82eab3e86f8fa77080a5d8d96a389a61ea1d0e3a94a582cf7"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c0abb5e4e8ce71a61d9446040c1e86d4e6d23f9097275c5bd49ed978755ff0fe"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:18300a1d78cf1290fa583cd8b7cde26ecb73e9f5916690cf9d42de569c89b1ce"}, - {file = "regex-2024.7.24-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:416c0e4f56308f34cdb18c3f59849479dde5b19febdcd6e6fa4d04b6c31c9faa"}, - {file = "regex-2024.7.24-cp310-cp310-win32.whl", hash = "sha256:fb168b5924bef397b5ba13aabd8cf5df7d3d93f10218d7b925e360d436863f66"}, - {file = "regex-2024.7.24-cp310-cp310-win_amd64.whl", hash = "sha256:6b9fc7e9cc983e75e2518496ba1afc524227c163e43d706688a6bb9eca41617e"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:382281306e3adaaa7b8b9ebbb3ffb43358a7bbf585fa93821300a418bb975281"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4fdd1384619f406ad9037fe6b6eaa3de2749e2e12084abc80169e8e075377d3b"}, - {file = "regex-2024.7.24-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3d974d24edb231446f708c455fd08f94c41c1ff4f04bcf06e5f36df5ef50b95a"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec4419a3fe6cf8a4795752596dfe0adb4aea40d3683a132bae9c30b81e8d73"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb563dd3aea54c797adf513eeec819c4213d7dbfc311874eb4fd28d10f2ff0f2"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45104baae8b9f67569f0f1dca5e1f1ed77a54ae1cd8b0b07aba89272710db61e"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:994448ee01864501912abf2bad9203bffc34158e80fe8bfb5b031f4f8e16da51"}, - {file = "regex-2024.7.24-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fac296f99283ac232d8125be932c5cd7644084a30748fda013028c815ba3364"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7e37e809b9303ec3a179085415cb5f418ecf65ec98cdfe34f6a078b46ef823ee"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:01b689e887f612610c869421241e075c02f2e3d1ae93a037cb14f88ab6a8934c"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f6442f0f0ff81775eaa5b05af8a0ffa1dda36e9cf6ec1e0d3d245e8564b684ce"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:871e3ab2838fbcb4e0865a6e01233975df3a15e6fce93b6f99d75cacbd9862d1"}, - {file = "regex-2024.7.24-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c918b7a1e26b4ab40409820ddccc5d49871a82329640f5005f73572d5eaa9b5e"}, - {file = "regex-2024.7.24-cp311-cp311-win32.whl", hash = "sha256:2dfbb8baf8ba2c2b9aa2807f44ed272f0913eeeba002478c4577b8d29cde215c"}, - {file = "regex-2024.7.24-cp311-cp311-win_amd64.whl", hash = "sha256:538d30cd96ed7d1416d3956f94d54e426a8daf7c14527f6e0d6d425fcb4cca52"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:fe4ebef608553aff8deb845c7f4f1d0740ff76fa672c011cc0bacb2a00fbde86"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:74007a5b25b7a678459f06559504f1eec2f0f17bca218c9d56f6a0a12bfffdad"}, - {file = "regex-2024.7.24-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7df9ea48641da022c2a3c9c641650cd09f0cd15e8908bf931ad538f5ca7919c9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a1141a1dcc32904c47f6846b040275c6e5de0bf73f17d7a409035d55b76f289"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80c811cfcb5c331237d9bad3bea2c391114588cf4131707e84d9493064d267f9"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7214477bf9bd195894cf24005b1e7b496f46833337b5dedb7b2a6e33f66d962c"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d55588cba7553f0b6ec33130bc3e114b355570b45785cebdc9daed8c637dd440"}, - {file = "regex-2024.7.24-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:558a57cfc32adcf19d3f791f62b5ff564922942e389e3cfdb538a23d65a6b610"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a512eed9dfd4117110b1881ba9a59b31433caed0c4101b361f768e7bcbaf93c5"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:86b17ba823ea76256b1885652e3a141a99a5c4422f4a869189db328321b73799"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5eefee9bfe23f6df09ffb6dfb23809f4d74a78acef004aa904dc7c88b9944b05"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:731fcd76bbdbf225e2eb85b7c38da9633ad3073822f5ab32379381e8c3c12e94"}, - {file = "regex-2024.7.24-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eaef80eac3b4cfbdd6de53c6e108b4c534c21ae055d1dbea2de6b3b8ff3def38"}, - {file = "regex-2024.7.24-cp312-cp312-win32.whl", hash = "sha256:185e029368d6f89f36e526764cf12bf8d6f0e3a2a7737da625a76f594bdfcbfc"}, - {file = "regex-2024.7.24-cp312-cp312-win_amd64.whl", hash = "sha256:2f1baff13cc2521bea83ab2528e7a80cbe0ebb2c6f0bfad15be7da3aed443908"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:66b4c0731a5c81921e938dcf1a88e978264e26e6ac4ec96a4d21ae0354581ae0"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:88ecc3afd7e776967fa16c80f974cb79399ee8dc6c96423321d6f7d4b881c92b"}, - {file = "regex-2024.7.24-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:64bd50cf16bcc54b274e20235bf8edbb64184a30e1e53873ff8d444e7ac656b2"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb462f0e346fcf41a901a126b50f8781e9a474d3927930f3490f38a6e73b6950"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a82465ebbc9b1c5c50738536fdfa7cab639a261a99b469c9d4c7dcbb2b3f1e57"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:68a8f8c046c6466ac61a36b65bb2395c74451df2ffb8458492ef49900efed293"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac8e84fff5d27420f3c1e879ce9929108e873667ec87e0c8eeb413a5311adfe"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba2537ef2163db9e6ccdbeb6f6424282ae4dea43177402152c67ef869cf3978b"}, - {file = "regex-2024.7.24-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:43affe33137fcd679bdae93fb25924979517e011f9dea99163f80b82eadc7e53"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:c9bb87fdf2ab2370f21e4d5636e5317775e5d51ff32ebff2cf389f71b9b13750"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:945352286a541406f99b2655c973852da7911b3f4264e010218bbc1cc73168f2"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:8bc593dcce679206b60a538c302d03c29b18e3d862609317cb560e18b66d10cf"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3f3b6ca8eae6d6c75a6cff525c8530c60e909a71a15e1b731723233331de4169"}, - {file = "regex-2024.7.24-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:c51edc3541e11fbe83f0c4d9412ef6c79f664a3745fab261457e84465ec9d5a8"}, - {file = "regex-2024.7.24-cp38-cp38-win32.whl", hash = "sha256:d0a07763776188b4db4c9c7fb1b8c494049f84659bb387b71c73bbc07f189e96"}, - {file = "regex-2024.7.24-cp38-cp38-win_amd64.whl", hash = "sha256:8fd5afd101dcf86a270d254364e0e8dddedebe6bd1ab9d5f732f274fa00499a5"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0ffe3f9d430cd37d8fa5632ff6fb36d5b24818c5c986893063b4e5bdb84cdf24"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:25419b70ba00a16abc90ee5fce061228206173231f004437730b67ac77323f0d"}, - {file = "regex-2024.7.24-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:33e2614a7ce627f0cdf2ad104797d1f68342d967de3695678c0cb84f530709f8"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d33a0021893ede5969876052796165bab6006559ab845fd7b515a30abdd990dc"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:04ce29e2c5fedf296b1a1b0acc1724ba93a36fb14031f3abfb7abda2806c1535"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b16582783f44fbca6fcf46f61347340c787d7530d88b4d590a397a47583f31dd"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:836d3cc225b3e8a943d0b02633fb2f28a66e281290302a79df0e1eaa984ff7c1"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438d9f0f4bc64e8dea78274caa5af971ceff0f8771e1a2333620969936ba10be"}, - {file = "regex-2024.7.24-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:973335b1624859cb0e52f96062a28aa18f3a5fc77a96e4a3d6d76e29811a0e6e"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c5e69fd3eb0b409432b537fe3c6f44ac089c458ab6b78dcec14478422879ec5f"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fbf8c2f00904eaf63ff37718eb13acf8e178cb940520e47b2f05027f5bb34ce3"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ae2757ace61bc4061b69af19e4689fa4416e1a04840f33b441034202b5cd02d4"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:44fc61b99035fd9b3b9453f1713234e5a7c92a04f3577252b45feefe1b327759"}, - {file = "regex-2024.7.24-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:84c312cdf839e8b579f504afcd7b65f35d60b6285d892b19adea16355e8343c9"}, - {file = "regex-2024.7.24-cp39-cp39-win32.whl", hash = "sha256:ca5b2028c2f7af4e13fb9fc29b28d0ce767c38c7facdf64f6c2cd040413055f1"}, - {file = "regex-2024.7.24-cp39-cp39-win_amd64.whl", hash = "sha256:7c479f5ae937ec9985ecaf42e2e10631551d909f203e31308c12d703922742f9"}, - {file = "regex-2024.7.24.tar.gz", hash = "sha256:9cfd009eed1a46b27c14039ad5bbc5e71b6367c5b2e6d5f5da0ea91600817506"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"}, + {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"}, + {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"}, + {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"}, + {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"}, + {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"}, + {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"}, + {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"}, + {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"}, + {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"}, + {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"}, + {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"}, + {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"}, + {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"}, + {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"}, + {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"}, + {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"}, + {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"}, + {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"}, + {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"}, + {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"}, + {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"}, + {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"}, + {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"}, + {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"}, + {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"}, + {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"}, + {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"}, + {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"}, + {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"}, + {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"}, + {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"}, ] [[package]] @@ -2925,23 +3101,23 @@ files = [ [[package]] name = "setuptools" -version = "74.1.1" +version = "75.6.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "setuptools-74.1.1-py3-none-any.whl", hash = "sha256:fc91b5f89e392ef5b77fe143b17e32f65d3024744fba66dc3afe07201684d766"}, - {file = "setuptools-74.1.1.tar.gz", hash = "sha256:2353af060c06388be1cecbf5953dcdb1f38362f87a2356c480b6b4d5fcfc8847"}, + {file = "setuptools-75.6.0-py3-none-any.whl", hash = "sha256:ce74b49e8f7110f9bf04883b730f4765b774ef3ef28f722cce7c273d253aaf7d"}, + {file = "setuptools-75.6.0.tar.gz", hash = "sha256:8199222558df7c86216af4f84c30e9b34a61d8ba19366cc914424cdbd28252f6"}, ] [package.extras] -check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.7.0)"] +core = ["importlib_metadata (>=6)", "jaraco.collections", "jaraco.functools (>=4)", "jaraco.text (>=3.7)", "more_itertools", "more_itertools (>=8.8)", "packaging", "packaging (>=24.2)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=24.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib_metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (>=1.12,<1.14)", "pytest-mypy"] [[package]] name = "six" @@ -2996,13 +3172,13 @@ files = [ [[package]] name = "tomli" -version = "2.0.1" +version = "2.1.0" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.1.0-py3-none-any.whl", hash = "sha256:a5c57c3d1c56f5ccdf89f6523458f60ef716e210fc47c4cfb188c5ba473e0391"}, + {file = "tomli-2.1.0.tar.gz", hash = "sha256:3f646cae2aec94e17d04973e4249548320197cfabdf130015d023de4b74d8ab8"}, ] [[package]] @@ -3039,13 +3215,13 @@ vulture = ["vulture (==2.7)"] [[package]] name = "toolz" -version = "0.12.1" +version = "1.0.0" description = "List processing tools and functional utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "toolz-0.12.1-py3-none-any.whl", hash = "sha256:d22731364c07d72eea0a0ad45bafb2c2937ab6fd38a3507bf55eae8744aa7d85"}, - {file = "toolz-0.12.1.tar.gz", hash = "sha256:ecca342664893f177a13dac0e6b41cbd8ac25a358e5f215316d43e2100224f4d"}, + {file = "toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236"}, + {file = "toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02"}, ] [[package]] @@ -3086,13 +3262,13 @@ files = [ [[package]] name = "urllib3" -version = "2.2.2" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, - {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -3160,13 +3336,13 @@ files = [ [[package]] name = "virtualenv" -version = "20.26.3" +version = "20.27.1" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, - {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, + {file = "virtualenv-20.27.1-py3-none-any.whl", hash = "sha256:f11f1b8a29525562925f745563bfd48b189450f61fb34c4f9cc79dd5aa32a1f4"}, + {file = "virtualenv-20.27.1.tar.gz", hash = "sha256:142c6be10212543b32c6c45d3d3893dff89112cc588b7d0879ae5a1ec03a47ba"}, ] [package.dependencies] @@ -3180,41 +3356,41 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess [[package]] name = "watchdog" -version = "5.0.2" +version = "6.0.0" description = "Filesystem events monitoring" optional = false python-versions = ">=3.9" files = [ - {file = "watchdog-5.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d961f4123bb3c447d9fcdcb67e1530c366f10ab3a0c7d1c0c9943050936d4877"}, - {file = "watchdog-5.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72990192cb63872c47d5e5fefe230a401b87fd59d257ee577d61c9e5564c62e5"}, - {file = "watchdog-5.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bec703ad90b35a848e05e1b40bf0050da7ca28ead7ac4be724ae5ac2653a1a0"}, - {file = "watchdog-5.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:dae7a1879918f6544201d33666909b040a46421054a50e0f773e0d870ed7438d"}, - {file = "watchdog-5.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c4a440f725f3b99133de610bfec93d570b13826f89616377715b9cd60424db6e"}, - {file = "watchdog-5.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8b2918c19e0d48f5f20df458c84692e2a054f02d9df25e6c3c930063eca64c1"}, - {file = "watchdog-5.0.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:aa9cd6e24126d4afb3752a3e70fce39f92d0e1a58a236ddf6ee823ff7dba28ee"}, - {file = "watchdog-5.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f627c5bf5759fdd90195b0c0431f99cff4867d212a67b384442c51136a098ed7"}, - {file = "watchdog-5.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7594a6d32cda2b49df3fd9abf9b37c8d2f3eab5df45c24056b4a671ac661619"}, - {file = "watchdog-5.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba32efcccfe2c58f4d01115440d1672b4eb26cdd6fc5b5818f1fb41f7c3e1889"}, - {file = "watchdog-5.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:963f7c4c91e3f51c998eeff1b3fb24a52a8a34da4f956e470f4b068bb47b78ee"}, - {file = "watchdog-5.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8c47150aa12f775e22efff1eee9f0f6beee542a7aa1a985c271b1997d340184f"}, - {file = "watchdog-5.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:14dd4ed023d79d1f670aa659f449bcd2733c33a35c8ffd88689d9d243885198b"}, - {file = "watchdog-5.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b84bff0391ad4abe25c2740c7aec0e3de316fdf7764007f41e248422a7760a7f"}, - {file = "watchdog-5.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e8d5ff39f0a9968952cce548e8e08f849141a4fcc1290b1c17c032ba697b9d7"}, - {file = "watchdog-5.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fb223456db6e5f7bd9bbd5cd969f05aae82ae21acc00643b60d81c770abd402b"}, - {file = "watchdog-5.0.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9814adb768c23727a27792c77812cf4e2fd9853cd280eafa2bcfa62a99e8bd6e"}, - {file = "watchdog-5.0.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:901ee48c23f70193d1a7bc2d9ee297df66081dd5f46f0ca011be4f70dec80dab"}, - {file = "watchdog-5.0.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:638bcca3d5b1885c6ec47be67bf712b00a9ab3d4b22ec0881f4889ad870bc7e8"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5597c051587f8757798216f2485e85eac583c3b343e9aa09127a3a6f82c65ee8"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_armv7l.whl", hash = "sha256:53ed1bf71fcb8475dd0ef4912ab139c294c87b903724b6f4a8bd98e026862e6d"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_i686.whl", hash = "sha256:29e4a2607bd407d9552c502d38b45a05ec26a8e40cc7e94db9bb48f861fa5abc"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_ppc64.whl", hash = "sha256:b6dc8f1d770a8280997e4beae7b9a75a33b268c59e033e72c8a10990097e5fde"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:d2ab34adc9bf1489452965cdb16a924e97d4452fcf88a50b21859068b50b5c3b"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_s390x.whl", hash = "sha256:7d1aa7e4bb0f0c65a1a91ba37c10e19dabf7eaaa282c5787e51371f090748f4b"}, - {file = "watchdog-5.0.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:726eef8f8c634ac6584f86c9c53353a010d9f311f6c15a034f3800a7a891d941"}, - {file = "watchdog-5.0.2-py3-none-win32.whl", hash = "sha256:bda40c57115684d0216556671875e008279dea2dc00fcd3dde126ac8e0d7a2fb"}, - {file = "watchdog-5.0.2-py3-none-win_amd64.whl", hash = "sha256:d010be060c996db725fbce7e3ef14687cdcc76f4ca0e4339a68cc4532c382a73"}, - {file = "watchdog-5.0.2-py3-none-win_ia64.whl", hash = "sha256:3960136b2b619510569b90f0cd96408591d6c251a75c97690f4553ca88889769"}, - {file = "watchdog-5.0.2.tar.gz", hash = "sha256:dcebf7e475001d2cdeb020be630dc5b687e9acdd60d16fea6bb4508e7b94cf76"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1cdb490583ebd691c012b3d6dae011000fe42edb7a82ece80965b42abd61f26"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bc64ab3bdb6a04d69d4023b29422170b74681784ffb9463ed4870cf2f3e66112"}, + {file = "watchdog-6.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c897ac1b55c5a1461e16dae288d22bb2e412ba9807df8397a635d88f671d36c3"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6eb11feb5a0d452ee41f824e271ca311a09e250441c262ca2fd7ebcf2461a06c"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef810fbf7b781a5a593894e4f439773830bdecb885e6880d957d5b9382a960d2"}, + {file = "watchdog-6.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:afd0fe1b2270917c5e23c2a65ce50c2a4abb63daafb0d419fde368e272a76b7c"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdd4e6f14b8b18c334febb9c4425a878a2ac20efd1e0b231978e7b150f92a948"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c7c15dda13c4eb00d6fb6fc508b3c0ed88b9d5d374056b239c4ad1611125c860"}, + {file = "watchdog-6.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6f10cb2d5902447c7d0da897e2c6768bca89174d0c6e1e30abec5421af97a5b0"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:490ab2ef84f11129844c23fb14ecf30ef3d8a6abafd3754a6f75ca1e6654136c"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:76aae96b00ae814b181bb25b1b98076d5fc84e8a53cd8885a318b42b6d3a5134"}, + {file = "watchdog-6.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a175f755fc2279e0b7312c0035d52e27211a5bc39719dd529625b1930917345b"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e6f0e77c9417e7cd62af82529b10563db3423625c5fce018430b249bf977f9e8"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90c8e78f3b94014f7aaae121e6b909674df5b46ec24d6bebc45c44c56729af2a"}, + {file = "watchdog-6.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e7631a77ffb1f7d2eefa4445ebbee491c720a5661ddf6df3498ebecae5ed375c"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c7ac31a19f4545dd92fc25d200694098f42c9a8e391bc00bdd362c5736dbf881"}, + {file = "watchdog-6.0.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9513f27a1a582d9808cf21a07dae516f0fab1cf2d7683a742c498b93eedabb11"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a0e56874cfbc4b9b05c60c8a1926fedf56324bb08cfbc188969777940aef3aa"}, + {file = "watchdog-6.0.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e6439e374fc012255b4ec786ae3c4bc838cd7309a540e5fe0952d03687d8804e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c"}, + {file = "watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2"}, + {file = "watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a"}, + {file = "watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680"}, + {file = "watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f"}, + {file = "watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282"}, ] [package.extras] @@ -3269,97 +3445,80 @@ six = "*" [[package]] name = "websockets" -version = "13.0.1" +version = "14.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1841c9082a3ba4a05ea824cf6d99570a6a2d8849ef0db16e9c826acb28089e8f"}, - {file = "websockets-13.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c5870b4a11b77e4caa3937142b650fbbc0914a3e07a0cf3131f35c0587489c1c"}, - {file = "websockets-13.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f1d3d1f2eb79fe7b0fb02e599b2bf76a7619c79300fc55f0b5e2d382881d4f7f"}, - {file = "websockets-13.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15c7d62ee071fa94a2fc52c2b472fed4af258d43f9030479d9c4a2de885fd543"}, - {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6724b554b70d6195ba19650fef5759ef11346f946c07dbbe390e039bcaa7cc3d"}, - {file = "websockets-13.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a952fa2ae57a42ba7951e6b2605e08a24801a4931b5644dfc68939e041bc7f"}, - {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17118647c0ea14796364299e942c330d72acc4b248e07e639d34b75067b3cdd8"}, - {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64a11aae1de4c178fa653b07d90f2fb1a2ed31919a5ea2361a38760192e1858b"}, - {file = "websockets-13.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0617fd0b1d14309c7eab6ba5deae8a7179959861846cbc5cb528a7531c249448"}, - {file = "websockets-13.0.1-cp310-cp310-win32.whl", hash = "sha256:11f9976ecbc530248cf162e359a92f37b7b282de88d1d194f2167b5e7ad80ce3"}, - {file = "websockets-13.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:c3c493d0e5141ec055a7d6809a28ac2b88d5b878bb22df8c621ebe79a61123d0"}, - {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:699ba9dd6a926f82a277063603fc8d586b89f4cb128efc353b749b641fcddda7"}, - {file = "websockets-13.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf2fae6d85e5dc384bf846f8243ddaa9197f3a1a70044f59399af001fd1f51d4"}, - {file = "websockets-13.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52aed6ef21a0f1a2a5e310fb5c42d7555e9c5855476bbd7173c3aa3d8a0302f2"}, - {file = "websockets-13.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8eb2b9a318542153674c6e377eb8cb9ca0fc011c04475110d3477862f15d29f0"}, - {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5df891c86fe68b2c38da55b7aea7095beca105933c697d719f3f45f4220a5e0e"}, - {file = "websockets-13.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fac2d146ff30d9dd2fcf917e5d147db037a5c573f0446c564f16f1f94cf87462"}, - {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b8ac5b46fd798bbbf2ac6620e0437c36a202b08e1f827832c4bf050da081b501"}, - {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:46af561eba6f9b0848b2c9d2427086cabadf14e0abdd9fde9d72d447df268418"}, - {file = "websockets-13.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b5a06d7f60bc2fc378a333978470dfc4e1415ee52f5f0fce4f7853eb10c1e9df"}, - {file = "websockets-13.0.1-cp311-cp311-win32.whl", hash = "sha256:556e70e4f69be1082e6ef26dcb70efcd08d1850f5d6c5f4f2bcb4e397e68f01f"}, - {file = "websockets-13.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:67494e95d6565bf395476e9d040037ff69c8b3fa356a886b21d8422ad86ae075"}, - {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f9c9e258e3d5efe199ec23903f5da0eeaad58cf6fccb3547b74fd4750e5ac47a"}, - {file = "websockets-13.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6b41a1b3b561f1cba8321fb32987552a024a8f67f0d05f06fcf29f0090a1b956"}, - {file = "websockets-13.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f73e676a46b0fe9426612ce8caeca54c9073191a77c3e9d5c94697aef99296af"}, - {file = "websockets-13.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f613289f4a94142f914aafad6c6c87903de78eae1e140fa769a7385fb232fdf"}, - {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f52504023b1480d458adf496dc1c9e9811df4ba4752f0bc1f89ae92f4f07d0c"}, - {file = "websockets-13.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:139add0f98206cb74109faf3611b7783ceafc928529c62b389917a037d4cfdf4"}, - {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:47236c13be337ef36546004ce8c5580f4b1150d9538b27bf8a5ad8edf23ccfab"}, - {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c44ca9ade59b2e376612df34e837013e2b273e6c92d7ed6636d0556b6f4db93d"}, - {file = "websockets-13.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9bbc525f4be3e51b89b2a700f5746c2a6907d2e2ef4513a8daafc98198b92237"}, - {file = "websockets-13.0.1-cp312-cp312-win32.whl", hash = "sha256:3624fd8664f2577cf8de996db3250662e259bfbc870dd8ebdcf5d7c6ac0b5185"}, - {file = "websockets-13.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0513c727fb8adffa6d9bf4a4463b2bade0186cbd8c3604ae5540fae18a90cb99"}, - {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1ee4cc030a4bdab482a37462dbf3ffb7e09334d01dd37d1063be1136a0d825fa"}, - {file = "websockets-13.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dbb0b697cc0655719522406c059eae233abaa3243821cfdfab1215d02ac10231"}, - {file = "websockets-13.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:acbebec8cb3d4df6e2488fbf34702cbc37fc39ac7abf9449392cefb3305562e9"}, - {file = "websockets-13.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63848cdb6fcc0bf09d4a155464c46c64ffdb5807ede4fb251da2c2692559ce75"}, - {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:872afa52a9f4c414d6955c365b6588bc4401272c629ff8321a55f44e3f62b553"}, - {file = "websockets-13.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05e70fec7c54aad4d71eae8e8cab50525e899791fc389ec6f77b95312e4e9920"}, - {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e82db3756ccb66266504f5a3de05ac6b32f287faacff72462612120074103329"}, - {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:4e85f46ce287f5c52438bb3703d86162263afccf034a5ef13dbe4318e98d86e7"}, - {file = "websockets-13.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f3fea72e4e6edb983908f0db373ae0732b275628901d909c382aae3b592589f2"}, - {file = "websockets-13.0.1-cp313-cp313-win32.whl", hash = "sha256:254ecf35572fca01a9f789a1d0f543898e222f7b69ecd7d5381d8d8047627bdb"}, - {file = "websockets-13.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca48914cdd9f2ccd94deab5bcb5ac98025a5ddce98881e5cce762854a5de330b"}, - {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b74593e9acf18ea5469c3edaa6b27fa7ecf97b30e9dabd5a94c4c940637ab96e"}, - {file = "websockets-13.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:132511bfd42e77d152c919147078460c88a795af16b50e42a0bd14f0ad71ddd2"}, - {file = "websockets-13.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:165bedf13556f985a2aa064309baa01462aa79bf6112fbd068ae38993a0e1f1b"}, - {file = "websockets-13.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e801ca2f448850685417d723ec70298feff3ce4ff687c6f20922c7474b4746ae"}, - {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30d3a1f041360f029765d8704eae606781e673e8918e6b2c792e0775de51352f"}, - {file = "websockets-13.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67648f5e50231b5a7f6d83b32f9c525e319f0ddc841be0de64f24928cd75a603"}, - {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:4f0426d51c8f0926a4879390f53c7f5a855e42d68df95fff6032c82c888b5f36"}, - {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ef48e4137e8799998a343706531e656fdec6797b80efd029117edacb74b0a10a"}, - {file = "websockets-13.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:249aab278810bee585cd0d4de2f08cfd67eed4fc75bde623be163798ed4db2eb"}, - {file = "websockets-13.0.1-cp38-cp38-win32.whl", hash = "sha256:06c0a667e466fcb56a0886d924b5f29a7f0886199102f0a0e1c60a02a3751cb4"}, - {file = "websockets-13.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1f3cf6d6ec1142412d4535adabc6bd72a63f5f148c43fe559f06298bc21953c9"}, - {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:1fa082ea38d5de51dd409434edc27c0dcbd5fed2b09b9be982deb6f0508d25bc"}, - {file = "websockets-13.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4a365bcb7be554e6e1f9f3ed64016e67e2fa03d7b027a33e436aecf194febb63"}, - {file = "websockets-13.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:10a0dc7242215d794fb1918f69c6bb235f1f627aaf19e77f05336d147fce7c37"}, - {file = "websockets-13.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59197afd478545b1f73367620407b0083303569c5f2d043afe5363676f2697c9"}, - {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d20516990d8ad557b5abeb48127b8b779b0b7e6771a265fa3e91767596d7d97"}, - {file = "websockets-13.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a1a2e272d067030048e1fe41aa1ec8cfbbaabce733b3d634304fa2b19e5c897f"}, - {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ad327ac80ba7ee61da85383ca8822ff808ab5ada0e4a030d66703cc025b021c4"}, - {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:518f90e6dd089d34eaade01101fd8a990921c3ba18ebbe9b0165b46ebff947f0"}, - {file = "websockets-13.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:68264802399aed6fe9652e89761031acc734fc4c653137a5911c2bfa995d6d6d"}, - {file = "websockets-13.0.1-cp39-cp39-win32.whl", hash = "sha256:a5dc0c42ded1557cc7c3f0240b24129aefbad88af4f09346164349391dea8e58"}, - {file = "websockets-13.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:b448a0690ef43db5ef31b3a0d9aea79043882b4632cfc3eaab20105edecf6097"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:faef9ec6354fe4f9a2c0bbb52fb1ff852effc897e2a4501e25eb3a47cb0a4f89"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:03d3f9ba172e0a53e37fa4e636b86cc60c3ab2cfee4935e66ed1d7acaa4625ad"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d450f5a7a35662a9b91a64aefa852f0c0308ee256122f5218a42f1d13577d71e"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f55b36d17ac50aa8a171b771e15fbe1561217510c8768af3d546f56c7576cdc"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14b9c006cac63772b31abbcd3e3abb6228233eec966bf062e89e7fa7ae0b7333"}, - {file = "websockets-13.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b79915a1179a91f6c5f04ece1e592e2e8a6bd245a0e45d12fd56b2b59e559a32"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f40de079779acbcdbb6ed4c65af9f018f8b77c5ec4e17a4b737c05c2db554491"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:80e4ba642fc87fa532bac07e5ed7e19d56940b6af6a8c61d4429be48718a380f"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a02b0161c43cc9e0232711eff846569fad6ec836a7acab16b3cf97b2344c060"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa74a45d4cdc028561a7d6ab3272c8b3018e23723100b12e58be9dfa5a24491"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:00fd961943b6c10ee6f0b1130753e50ac5dcd906130dcd77b0003c3ab797d026"}, - {file = "websockets-13.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d93572720d781331fb10d3da9ca1067817d84ad1e7c31466e9f5e59965618096"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:71e6e5a3a3728886caee9ab8752e8113670936a193284be9d6ad2176a137f376"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:c4a6343e3b0714e80da0b0893543bf9a5b5fa71b846ae640e56e9abc6fbc4c83"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a678532018e435396e37422a95e3ab87f75028ac79570ad11f5bf23cd2a7d8c"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6716c087e4aa0b9260c4e579bb82e068f84faddb9bfba9906cb87726fa2e870"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e33505534f3f673270dd67f81e73550b11de5b538c56fe04435d63c02c3f26b5"}, - {file = "websockets-13.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:acab3539a027a85d568c2573291e864333ec9d912675107d6efceb7e2be5d980"}, - {file = "websockets-13.0.1-py3-none-any.whl", hash = "sha256:b80f0c51681c517604152eb6a572f5a9378f877763231fddb883ba2f968e8817"}, - {file = "websockets-13.0.1.tar.gz", hash = "sha256:4d6ece65099411cfd9a48d13701d7438d9c34f479046b34c50ff60bb8834e43e"}, + {file = "websockets-14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a0adf84bc2e7c86e8a202537b4fd50e6f7f0e4a6b6bf64d7ccb96c4cd3330b29"}, + {file = "websockets-14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90b5d9dfbb6d07a84ed3e696012610b6da074d97453bd01e0e30744b472c8179"}, + {file = "websockets-14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2177ee3901075167f01c5e335a6685e71b162a54a89a56001f1c3e9e3d2ad250"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f14a96a0034a27f9d47fd9788913924c89612225878f8078bb9d55f859272b0"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f874ba705deea77bcf64a9da42c1f5fc2466d8f14daf410bc7d4ceae0a9fcb0"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bea45f19b7ca000380fbd4e02552be86343080120d074b87f25593ce1700ad58"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:219c8187b3ceeadbf2afcf0f25a4918d02da7b944d703b97d12fb01510869078"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad2ab2547761d79926effe63de21479dfaf29834c50f98c4bf5b5480b5838434"}, + {file = "websockets-14.1-cp310-cp310-win32.whl", hash = "sha256:1288369a6a84e81b90da5dbed48610cd7e5d60af62df9851ed1d1d23a9069f10"}, + {file = "websockets-14.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0744623852f1497d825a49a99bfbec9bea4f3f946df6eb9d8a2f0c37a2fec2e"}, + {file = "websockets-14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512"}, + {file = "websockets-14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac"}, + {file = "websockets-14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23"}, + {file = "websockets-14.1-cp311-cp311-win32.whl", hash = "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e"}, + {file = "websockets-14.1-cp311-cp311-win_amd64.whl", hash = "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09"}, + {file = "websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed"}, + {file = "websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d"}, + {file = "websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05"}, + {file = "websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0"}, + {file = "websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f"}, + {file = "websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9"}, + {file = "websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b"}, + {file = "websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a"}, + {file = "websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6"}, + {file = "websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0"}, + {file = "websockets-14.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01bb2d4f0a6d04538d3c5dfd27c0643269656c28045a53439cbf1c004f90897a"}, + {file = "websockets-14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:414ffe86f4d6f434a8c3b7913655a1a5383b617f9bf38720e7c0799fac3ab1c6"}, + {file = "websockets-14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fda642151d5affdee8a430bd85496f2e2517be3a2b9d2484d633d5712b15c56"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd7c11968bc3860d5c78577f0dbc535257ccec41750675d58d8dc66aa47fe52c"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a032855dc7db987dff813583d04f4950d14326665d7e714d584560b140ae6b8b"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7e7ea2f782408c32d86b87a0d2c1fd8871b0399dd762364c731d86c86069a78"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:39450e6215f7d9f6f7bc2a6da21d79374729f5d052333da4d5825af8a97e6735"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ceada5be22fa5a5a4cdeec74e761c2ee7db287208f54c718f2df4b7e200b8d4a"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3fc753451d471cff90b8f467a1fc0ae64031cf2d81b7b34e1811b7e2691bc4bc"}, + {file = "websockets-14.1-cp39-cp39-win32.whl", hash = "sha256:14839f54786987ccd9d03ed7f334baec0f02272e7ec4f6e9d427ff584aeea8b4"}, + {file = "websockets-14.1-cp39-cp39-win_amd64.whl", hash = "sha256:d9fd19ecc3a4d5ae82ddbfb30962cf6d874ff943e56e0c81f5169be2fda62979"}, + {file = "websockets-14.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5dc25a9dbd1a7f61eca4b7cb04e74ae4b963d658f9e4f9aad9cd00b688692c8"}, + {file = "websockets-14.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:04a97aca96ca2acedf0d1f332c861c5a4486fdcba7bcef35873820f940c4231e"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df174ece723b228d3e8734a6f2a6febbd413ddec39b3dc592f5a4aa0aff28098"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:034feb9f4286476f273b9a245fb15f02c34d9586a5bc936aff108c3ba1b21beb"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c308dabd2b380807ab64b62985eaccf923a78ebc572bd485375b9ca2b7dc7"}, + {file = "websockets-14.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a42d3ecbb2db5080fc578314439b1d79eef71d323dc661aa616fb492436af5d"}, + {file = "websockets-14.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddaa4a390af911da6f680be8be4ff5aaf31c4c834c1a9147bc21cbcbca2d4370"}, + {file = "websockets-14.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a4c805c6034206143fbabd2d259ec5e757f8b29d0a2f0bf3d2fe5d1f60147a4a"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:205f672a6c2c671a86d33f6d47c9b35781a998728d2c7c2a3e1cf3333fcb62b7"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef440054124728cc49b01c33469de06755e5a7a4e83ef61934ad95fc327fbb0"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7591d6f440af7f73c4bd9404f3772bfee064e639d2b6cc8c94076e71b2471c1"}, + {file = "websockets-14.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:25225cc79cfebc95ba1d24cd3ab86aaa35bcd315d12fa4358939bd55e9bd74a5"}, + {file = "websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e"}, + {file = "websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8"}, ] [[package]] @@ -3378,118 +3537,109 @@ watchdog = ["watchdog"] [[package]] name = "yarl" -version = "1.9.8" +version = "1.17.2" description = "Yet another URL library" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "yarl-1.9.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:08359dbc3540fafa8972db45d3ef2d61370b4c24b8a028a4301bc5d076eee0e2"}, - {file = "yarl-1.9.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a7a716aae4fcecadfe4648268d3c194315152715391f4af6fad50d502be122e9"}, - {file = "yarl-1.9.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:62223670042a219b8e6fbd2c7f35c456278dcd346d3aba3f2c01c9bdec28f37e"}, - {file = "yarl-1.9.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18097a9e50ea31c61fece83bac8f63263f0c0c16c439bf82ac729c23f3b170e3"}, - {file = "yarl-1.9.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5809f8a48c8dab91f708947d358271ef1890c3012d6c45719f49d04af2112057"}, - {file = "yarl-1.9.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71ff7a22355241f89e850afbc8858fb671ba7e2763af32ebbea158d23a84902a"}, - {file = "yarl-1.9.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d54e9880e781a490483200a74f6314fb6cf692a8197ccde93adf32bec95626b"}, - {file = "yarl-1.9.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ad8ea6ab27e27821739dfb94fab63284e3a52055e268f04529dc082fd0d59a2"}, - {file = "yarl-1.9.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b79e031524259b51cdd1ea41f5053491ad3565b9cecd76389c9f705752d14283"}, - {file = "yarl-1.9.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bd91ccded75d080f13ed01a5f5796887916d2e8c0999cd68bcb58f89f9b1c29c"}, - {file = "yarl-1.9.8-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:583f48ab25b3906e3716479e8f700c4cc487e44d52766a4ea52b01cb7ea772d6"}, - {file = "yarl-1.9.8-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2f3e89838acdaf5bbd69383c408d9e119b4e9efbe8a38fa40045b5c966f918e3"}, - {file = "yarl-1.9.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a44c0b83d1871e1e1859167a1804143f590f86ac4708380852dca4d8299d8594"}, - {file = "yarl-1.9.8-cp310-cp310-win32.whl", hash = "sha256:5d39ae58a67b64b470021d18a13529d0c58efc5bf057936ec4b29092d4061030"}, - {file = "yarl-1.9.8-cp310-cp310-win_amd64.whl", hash = "sha256:f89ade31926b9931bbe29f5c62d4174057e532fb0c72e2e6abdd129fda6a60f3"}, - {file = "yarl-1.9.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:986296e65b0312c1da168de4ec1bb054b4a7b0ec26e3f9e8dafc06bbb1385030"}, - {file = "yarl-1.9.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b4c7c015dc813aa5fe15379f3540d178e3743c0f1cf9e4a4a8bff94bd2832a4d"}, - {file = "yarl-1.9.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:22b2db22f72e1cb8a552ae12dfb748167153c7cbf353c62781915b5328bf2561"}, - {file = "yarl-1.9.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a567416bfb2a2b093aa64685aa7b6dfb593888784ef91b16fa6b985cceb951"}, - {file = "yarl-1.9.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:178f4ab054f3a5dc84c8091bd7395b6713aac83af893b62259d5eb3f5359ce7f"}, - {file = "yarl-1.9.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02fe9809b29a7dc4a27b769a43c556288d949205db54338871a122b64751e0f4"}, - {file = "yarl-1.9.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c885a81f6c89b0d45fc0dd88e005c77dd8ba1dac421466d0dbb9192ce6d34e1e"}, - {file = "yarl-1.9.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99f78f45c8b4c9824e1a37eb0a3ae63ad2dff66434d9620265a4256088be9cda"}, - {file = "yarl-1.9.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:30929a10be9a13026fd68377aba3223d633370abb93dadd3932754f3dcf4734a"}, - {file = "yarl-1.9.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ee7c00a1979b3f23c8094dce6d9875453b3cb91b1153d9efaefa6773cf80cdb0"}, - {file = "yarl-1.9.8-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e89d76b2aa11287f038a37577528c5f62d9385020b795a011f60dfd1b217cf9f"}, - {file = "yarl-1.9.8-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:81fde88456d2cbe005e16aca78ef744f322b3b15184dfe41b5b04f97b46aa5be"}, - {file = "yarl-1.9.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b3dca0a4e192207f8bb4057725ff95e9a14d53a04728742f2b03692fc91b0a43"}, - {file = "yarl-1.9.8-cp311-cp311-win32.whl", hash = "sha256:9ea3a8532ea9fc2eeb6fc3def0c341aaeab7625545844f9c0a15350c17f9f479"}, - {file = "yarl-1.9.8-cp311-cp311-win_amd64.whl", hash = "sha256:c810606719683f4ab92127712efe283674d6ed29a627374411c762852913c2dd"}, - {file = "yarl-1.9.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b3d373373908e687aa4c8b0666870b0cf65605254ba0819ed8d5af2fc0780496"}, - {file = "yarl-1.9.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e3d1be58e28825a14fb9561733de62fbe95c892febe7d7a9ebcde916c531d603"}, - {file = "yarl-1.9.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7318736a8ee9de8217d590866dd716fa3c0895e684e2ec6152d945a4ab758043"}, - {file = "yarl-1.9.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db3dd602cbf6613dc1e4a6fbde7a1bee86948e5940086090bb505c2ab959bbdf"}, - {file = "yarl-1.9.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5950226b128a1610f57c1f756fc611fdbdcb1e6b4497ccb05fce76a38915b07"}, - {file = "yarl-1.9.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b341a995673180ed81a1040228a59e0b47ee687e367b1a03d829fa3c0eb4607e"}, - {file = "yarl-1.9.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f912153a34698994f32cf683d966014b0dd99c73481302d6159bcb3a8303e84"}, - {file = "yarl-1.9.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9ceab2b16043ae1953863ec240eb918ba1ac40d2aad55225141aac288c606442"}, - {file = "yarl-1.9.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7c0d2bc2646ae2380bb91b9ddc2eb1e1fa6baef128499e817134d1d50c8b6c56"}, - {file = "yarl-1.9.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ebd98e16ff9948e4d31514c937275017a122b765cb89961dd5d44ecd2cc18140"}, - {file = "yarl-1.9.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:83273ca458c85d7b026c770a86df6e36349e85100bd2cefe6d0ad7167a8f12a6"}, - {file = "yarl-1.9.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4511dd73b6aeda0cc39111839923f1545726d621813c9d13355824fba328dbcf"}, - {file = "yarl-1.9.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ffb9f1cad56c547aa127e2c315e666ee9838156c8a3b14f37ba545b0167aa5e"}, - {file = "yarl-1.9.8-cp312-cp312-win32.whl", hash = "sha256:5796358c3d6c72b108b570e20ab951463237ec473b6d204da21050feaaaf7dca"}, - {file = "yarl-1.9.8-cp312-cp312-win_amd64.whl", hash = "sha256:c2dc6e941bf53160b44858d1b24767a056cd83166b69fbdd3b2e401856d8932e"}, - {file = "yarl-1.9.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:cb3d488f049db9522e3a0de50e07bac0c53565acd88a07bc9cf7182fd6890307"}, - {file = "yarl-1.9.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:50cbf73b6a4b62c3ad633e8920f2791adf485356ef37c9edbd5a1e7de8da2ddc"}, - {file = "yarl-1.9.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b1e0649ee7ac354a3e40ee849707140b14a2cd0cd2dc2062fe620458dfe465c8"}, - {file = "yarl-1.9.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2501b230e89cad2361719860648f780197812d3be91c7ca6658a097a7e22fc4"}, - {file = "yarl-1.9.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be441a73f9f49427906274008bd98384d8ca4655981735281c314fc7c145d256"}, - {file = "yarl-1.9.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7de1968a1c2690b86e32e91acf8ed2043c346293f9bbe1704b9f6a481b73bd11"}, - {file = "yarl-1.9.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce892a75a2209cf4f7007de21c6f6d607f4b9406ac613a59ad02340f6e933e4"}, - {file = "yarl-1.9.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:405e75bb94b87cc4167eef0e08d6a539f60633229f7043edc2e65c82ef80e874"}, - {file = "yarl-1.9.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bc5811c1906b38f2a203df1266c6dd11680ca85d610d6ee3701dde262a305520"}, - {file = "yarl-1.9.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:51476f19fe1296d3efe3770179548f5f4822e5c4ead9f5160ba156a6a9f5272c"}, - {file = "yarl-1.9.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ce2af144a81883db914636bec646da4dcccfe9db05c2899e7afe90a3d817ffce"}, - {file = "yarl-1.9.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:8c91b71b0af1fb5454709e34b39e38c975faaa89c0cc8bb744d60300ca710fcd"}, - {file = "yarl-1.9.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:1a562055b5ec6371c307320e8460d16675244e810b20f343371fc52797d23615"}, - {file = "yarl-1.9.8-cp313-cp313-win32.whl", hash = "sha256:f7442a9342aa04ea60b760a8f0d210e269f881eb0660a2000fa1f8cb89820931"}, - {file = "yarl-1.9.8-cp313-cp313-win_amd64.whl", hash = "sha256:21ef75d8a18fa47725b50fcb7ae6d23a51c71a7426cdf7097e52f9e12a995eb6"}, - {file = "yarl-1.9.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:fd9affa8c18198dfa5a19c63b29ef2a2f35b8efacaf0bdd3e58f974c0ab0108d"}, - {file = "yarl-1.9.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f79e65f16413a95d9f7633802a2ee34730b3ba1dd0af82811b377057883c4fb7"}, - {file = "yarl-1.9.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3f8c454cf7e4d3762515ed2b5a40cf2feaeb8a8ed1d121f131a6178e16015319"}, - {file = "yarl-1.9.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f972fc63a1d6165d1cff650a16a498b0087334f7f9cd7385860c086d009cd49"}, - {file = "yarl-1.9.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ac4aa2f2d8253b9a5455d5f0ed45687ea9715b78a563490ddf7954337974cb7"}, - {file = "yarl-1.9.8-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b001379047de5e03224dc0592f1b0e60738857a9b992d9b636b5050500ecce23"}, - {file = "yarl-1.9.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39deb5a67b591682e54d1b09b36e79cd608ca27bea1fefed3bcaaa0b05d2b25e"}, - {file = "yarl-1.9.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffd9dd7eac5d36f53fccdf11e98730b7a628561c77f6c2a9e0909d2a304f34d1"}, - {file = "yarl-1.9.8-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:497d5fd7dce44b5dcac648c830c99a673d30bc6cd9905b3e255c92c6dc01f537"}, - {file = "yarl-1.9.8-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:d99011d564f2b5cb4cf1012f9058e08d8d79674332474f7e940131f5952015df"}, - {file = "yarl-1.9.8-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:600f734296cb99db1af7e34c0dcf8ec9477072f72c4621677637fdc2273af120"}, - {file = "yarl-1.9.8-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:6703deac7bb0dd8b3f0bc3cb6844dab4e74c85c70783ae89bd0b52286ebdc102"}, - {file = "yarl-1.9.8-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3346e2f641fcf31cf32c5a394d625e0676aba6fadccc06d35435e475753ed05d"}, - {file = "yarl-1.9.8-cp38-cp38-win32.whl", hash = "sha256:a54f7a63e48156a77a7c0333cefed29ceb004ab683d685a1192b341ac445cb73"}, - {file = "yarl-1.9.8-cp38-cp38-win_amd64.whl", hash = "sha256:45992ff8d941a1901c35f2ed90a60cb5fee8705ffadff395db4a5fd164473542"}, - {file = "yarl-1.9.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:590437f092af08e71521cc302940ef897e969152434c825bb3fb8f308b63a8bb"}, - {file = "yarl-1.9.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:551c26789acd38c7b90a89a1f262291d9f9a6a677185a83b5781e2a2c4258aec"}, - {file = "yarl-1.9.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:121bf7d647b3f6481ce1030350c1cc4c43e18758010732a449c71a1784ae793d"}, - {file = "yarl-1.9.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c9db466370e8bc3459912850494ad3401f3664ff3a56842f0d4514166f54c9f"}, - {file = "yarl-1.9.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff56e21379824f3e3c39a37083d5ab905168b9483b1c0c563dd92eb2db18b251"}, - {file = "yarl-1.9.8-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cce910a1510d60c7eff4bb263b28b9afdcc5f6b85c555e492cfe7548a09e2476"}, - {file = "yarl-1.9.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ba7c4b50cc0bb4caaa54554613ca13db47a24878a4fc1063e6303494fc67567"}, - {file = "yarl-1.9.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b345de5e725b82e9458dc1381d7e28fe7d7ef93491370461dc98283b9dda51e2"}, - {file = "yarl-1.9.8-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:49dd58b79b0fd04e880c90bc570fde68407cc516c58812f0321f5e74c131107c"}, - {file = "yarl-1.9.8-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:15fb127bcc19065fd912391a43bc80114635f0062e0465765633ab5d0c7fc3a1"}, - {file = "yarl-1.9.8-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:6f4f87a7c97ba77fdc764b893ae4083c74e5857904962a70025ade0cd42bdbaf"}, - {file = "yarl-1.9.8-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:d336601d9ff3dc3b12263739ab1add25bdd2345d675f59ad49f72d9a6ccbc865"}, - {file = "yarl-1.9.8-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3574834e4aaf24e24d12fa4fd53d0b0fd1d70b24a67bed81c44b284377e81d45"}, - {file = "yarl-1.9.8-cp39-cp39-win32.whl", hash = "sha256:db9305328486539bb7182c15f1ad1ea95dae52245e93a049f2b1d6f04e63674d"}, - {file = "yarl-1.9.8-cp39-cp39-win_amd64.whl", hash = "sha256:588d62a57c7a43b230557728ec9f252b3f81ad073cb5c0ef48d87cd3f8b6ace2"}, - {file = "yarl-1.9.8-py3-none-any.whl", hash = "sha256:d1612ce50f23b94897b9ef5eb65b72398a9a83ea990b42825272590f3484dae3"}, - {file = "yarl-1.9.8.tar.gz", hash = "sha256:3089553548d9ab23152cecb5a71131caaa9e9b16d7fc8196057c374fdc53cc4b"}, + {file = "yarl-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:93771146ef048b34201bfa382c2bf74c524980870bb278e6df515efaf93699ff"}, + {file = "yarl-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8281db240a1616af2f9c5f71d355057e73a1409c4648c8949901396dc0a3c151"}, + {file = "yarl-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:170ed4971bf9058582b01a8338605f4d8c849bd88834061e60e83b52d0c76870"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc61b005f6521fcc00ca0d1243559a5850b9dd1e1fe07b891410ee8fe192d0c0"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:871e1b47eec7b6df76b23c642a81db5dd6536cbef26b7e80e7c56c2fd371382e"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a58a2f2ca7aaf22b265388d40232f453f67a6def7355a840b98c2d547bd037f"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:736bb076f7299c5c55dfef3eb9e96071a795cb08052822c2bb349b06f4cb2e0a"}, + {file = "yarl-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8fd51299e21da709eabcd5b2dd60e39090804431292daacbee8d3dabe39a6bc0"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:358dc7ddf25e79e1cc8ee16d970c23faee84d532b873519c5036dbb858965795"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:50d866f7b1a3f16f98603e095f24c0eeba25eb508c85a2c5939c8b3870ba2df8"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:8b9c4643e7d843a0dca9cd9d610a0876e90a1b2cbc4c5ba7930a0d90baf6903f"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d63123bfd0dce5f91101e77c8a5427c3872501acece8c90df457b486bc1acd47"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:4e76381be3d8ff96a4e6c77815653063e87555981329cf8f85e5be5abf449021"}, + {file = "yarl-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:734144cd2bd633a1516948e477ff6c835041c0536cef1d5b9a823ae29899665b"}, + {file = "yarl-1.17.2-cp310-cp310-win32.whl", hash = "sha256:26bfb6226e0c157af5da16d2d62258f1ac578d2899130a50433ffee4a5dfa673"}, + {file = "yarl-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:76499469dcc24759399accd85ec27f237d52dec300daaca46a5352fcbebb1071"}, + {file = "yarl-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:792155279dc093839e43f85ff7b9b6493a8eaa0af1f94f1f9c6e8f4de8c63500"}, + {file = "yarl-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:38bc4ed5cae853409cb193c87c86cd0bc8d3a70fd2268a9807217b9176093ac6"}, + {file = "yarl-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4a8c83f6fcdc327783bdc737e8e45b2e909b7bd108c4da1892d3bc59c04a6d84"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6d5fed96f0646bfdf698b0a1cebf32b8aae6892d1bec0c5d2d6e2df44e1e2d"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:782ca9c58f5c491c7afa55518542b2b005caedaf4685ec814fadfcee51f02493"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff6af03cac0d1a4c3c19e5dcc4c05252411bf44ccaa2485e20d0a7c77892ab6e"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a3f47930fbbed0f6377639503848134c4aa25426b08778d641491131351c2c8"}, + {file = "yarl-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1fa68a3c921365c5745b4bd3af6221ae1f0ea1bf04b69e94eda60e57958907f"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:187df91395c11e9f9dc69b38d12406df85aa5865f1766a47907b1cc9855b6303"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:93d1c8cc5bf5df401015c5e2a3ce75a5254a9839e5039c881365d2a9dcfc6dc2"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:11d86c6145ac5c706c53d484784cf504d7d10fa407cb73b9d20f09ff986059ef"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c42774d1d1508ec48c3ed29e7b110e33f5e74a20957ea16197dbcce8be6b52ba"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8e589379ef0407b10bed16cc26e7392ef8f86961a706ade0a22309a45414d7"}, + {file = "yarl-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1056cadd5e850a1c026f28e0704ab0a94daaa8f887ece8dfed30f88befb87bb0"}, + {file = "yarl-1.17.2-cp311-cp311-win32.whl", hash = "sha256:be4c7b1c49d9917c6e95258d3d07f43cfba2c69a6929816e77daf322aaba6628"}, + {file = "yarl-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:ac8eda86cc75859093e9ce390d423aba968f50cf0e481e6c7d7d63f90bae5c9c"}, + {file = "yarl-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dd90238d3a77a0e07d4d6ffdebc0c21a9787c5953a508a2231b5f191455f31e9"}, + {file = "yarl-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c74f0b0472ac40b04e6d28532f55cac8090e34c3e81f118d12843e6df14d0909"}, + {file = "yarl-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d486ddcaca8c68455aa01cf53d28d413fb41a35afc9f6594a730c9779545876"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25b7e93f5414b9a983e1a6c1820142c13e1782cc9ed354c25e933aebe97fcf2"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a0baff7827a632204060f48dca9e63fbd6a5a0b8790c1a2adfb25dc2c9c0d50"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:460024cacfc3246cc4d9f47a7fc860e4fcea7d1dc651e1256510d8c3c9c7cde0"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5870d620b23b956f72bafed6a0ba9a62edb5f2ef78a8849b7615bd9433384171"}, + {file = "yarl-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2941756754a10e799e5b87e2319bbec481ed0957421fba0e7b9fb1c11e40509f"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9611b83810a74a46be88847e0ea616794c406dbcb4e25405e52bff8f4bee2d0a"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:cd7e35818d2328b679a13268d9ea505c85cd773572ebb7a0da7ccbca77b6a52e"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6b981316fcd940f085f646b822c2ff2b8b813cbd61281acad229ea3cbaabeb6b"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:688058e89f512fb7541cb85c2f149c292d3fa22f981d5a5453b40c5da49eb9e8"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56afb44a12b0864d17b597210d63a5b88915d680f6484d8d202ed68ade38673d"}, + {file = "yarl-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:17931dfbb84ae18b287279c1f92b76a3abcd9a49cd69b92e946035cff06bcd20"}, + {file = "yarl-1.17.2-cp312-cp312-win32.whl", hash = "sha256:ff8d95e06546c3a8c188f68040e9d0360feb67ba8498baf018918f669f7bc39b"}, + {file = "yarl-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:4c840cc11163d3c01a9d8aad227683c48cd3e5be5a785921bcc2a8b4b758c4f3"}, + {file = "yarl-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3294f787a437cb5d81846de3a6697f0c35ecff37a932d73b1fe62490bef69211"}, + {file = "yarl-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f1e7fedb09c059efee2533119666ca7e1a2610072076926fa028c2ba5dfeb78c"}, + {file = "yarl-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:da9d3061e61e5ae3f753654813bc1cd1c70e02fb72cf871bd6daf78443e9e2b1"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91c012dceadc695ccf69301bfdccd1fc4472ad714fe2dd3c5ab4d2046afddf29"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f11fd61d72d93ac23718d393d2a64469af40be2116b24da0a4ca6922df26807e"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46c465ad06971abcf46dd532f77560181387b4eea59084434bdff97524444032"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef6eee1a61638d29cd7c85f7fd3ac7b22b4c0fabc8fd00a712b727a3e73b0685"}, + {file = "yarl-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4434b739a8a101a837caeaa0137e0e38cb4ea561f39cb8960f3b1e7f4967a3fc"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:752485cbbb50c1e20908450ff4f94217acba9358ebdce0d8106510859d6eb19a"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:17791acaa0c0f89323c57da7b9a79f2174e26d5debbc8c02d84ebd80c2b7bff8"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5c6ea72fe619fee5e6b5d4040a451d45d8175f560b11b3d3e044cd24b2720526"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db5ac3871ed76340210fe028f535392f097fb31b875354bcb69162bba2632ef4"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:7a1606ba68e311576bcb1672b2a1543417e7e0aa4c85e9e718ba6466952476c0"}, + {file = "yarl-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9bc27dd5cfdbe3dc7f381b05e6260ca6da41931a6e582267d5ca540270afeeb2"}, + {file = "yarl-1.17.2-cp313-cp313-win32.whl", hash = "sha256:52492b87d5877ec405542f43cd3da80bdcb2d0c2fbc73236526e5f2c28e6db28"}, + {file = "yarl-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:8e1bf59e035534ba4077f5361d8d5d9194149f9ed4f823d1ee29ef3e8964ace3"}, + {file = "yarl-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c556fbc6820b6e2cda1ca675c5fa5589cf188f8da6b33e9fc05b002e603e44fa"}, + {file = "yarl-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f2f44a4247461965fed18b2573f3a9eb5e2c3cad225201ee858726cde610daca"}, + {file = "yarl-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3a3ede8c248f36b60227eb777eac1dbc2f1022dc4d741b177c4379ca8e75571a"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2654caaf5584449d49c94a6b382b3cb4a246c090e72453493ea168b931206a4d"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d41c684f286ce41fa05ab6af70f32d6da1b6f0457459a56cf9e393c1c0b2217"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2270d590997445a0dc29afa92e5534bfea76ba3aea026289e811bf9ed4b65a7f"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18662443c6c3707e2fc7fad184b4dc32dd428710bbe72e1bce7fe1988d4aa654"}, + {file = "yarl-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75ac158560dec3ed72f6d604c81090ec44529cfb8169b05ae6fcb3e986b325d9"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1fee66b32e79264f428dc8da18396ad59cc48eef3c9c13844adec890cd339db5"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:585ce7cd97be8f538345de47b279b879e091c8b86d9dbc6d98a96a7ad78876a3"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c019abc2eca67dfa4d8fb72ba924871d764ec3c92b86d5b53b405ad3d6aa56b0"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c6e659b9a24d145e271c2faf3fa6dd1fcb3e5d3f4e17273d9e0350b6ab0fe6e2"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:d17832ba39374134c10e82d137e372b5f7478c4cceeb19d02ae3e3d1daed8721"}, + {file = "yarl-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bc3003710e335e3f842ae3fd78efa55f11a863a89a72e9a07da214db3bf7e1f8"}, + {file = "yarl-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f5ffc6b7ace5b22d9e73b2a4c7305740a339fbd55301d52735f73e21d9eb3130"}, + {file = "yarl-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:48e424347a45568413deec6f6ee2d720de2cc0385019bedf44cd93e8638aa0ed"}, + {file = "yarl-1.17.2-py3-none-any.whl", hash = "sha256:dd7abf4f717e33b7487121faf23560b3a50924f80e4bef62b22dab441ded8f3b"}, + {file = "yarl-1.17.2.tar.gz", hash = "sha256:753eaaa0c7195244c84b5cc159dc8204b7fd99f716f11198f999f2332a86b178"}, ] [package.dependencies] idna = ">=2.0" multidict = ">=4.0" +propcache = ">=0.2.0" [[package]] name = "zipp" -version = "3.20.1" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"}, - {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] @@ -3503,4 +3653,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "<3.12,>=3.9" -content-hash = "0c3dee80f18869f08b05c0cb56897d158e201cd4e0e4baacaa84954eac63dcea" +content-hash = "b75277aad08d587ce11fa395aea10930ac7abac3fe7f3ad48e10dc0af70ffc05" diff --git a/pyproject.toml b/pyproject.toml index def9463c0..a511e5d70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,11 +19,11 @@ operate = "operate.cli:main" [tool.poetry.dependencies] python = "<3.12,>=3.9" -open-autonomy = "==0.14.14.post2" -open-aea-ledger-cosmos = "==1.53.0" -open-aea-ledger-ethereum = "==1.53.0" -open-aea-ledger-ethereum-flashbots = "==1.53.0" -open-aea-cli-ipfs = "==1.53.0" +open-autonomy = "==0.16.1" +open-aea-ledger-cosmos = "==1.57.0" +open-aea-ledger-ethereum = "==1.57.0" +open-aea-ledger-ethereum-flashbots = "==1.57.0" +open-aea-cli-ipfs = "==1.57.0" clea = "==0.1.0rc4" cytoolz = "==0.12.3" docker = "6.1.2" From 38c4127d9e0eb3fa0a35b3170f535b909d47d081 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 16:56:21 +0000 Subject: [PATCH 329/463] feat: refactor SettingsPage to use master wallet context and improve backup address handling --- frontend/components/SettingsPage/index.tsx | 42 ++++++++++++++++------ frontend/hooks/useMultisig.ts | 9 +++-- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/frontend/components/SettingsPage/index.tsx b/frontend/components/SettingsPage/index.tsx index e12725c97..a3c97cf18 100644 --- a/frontend/components/SettingsPage/index.tsx +++ b/frontend/components/SettingsPage/index.tsx @@ -1,5 +1,6 @@ import { CloseOutlined, SettingOutlined } from '@ant-design/icons'; import { Button, Card, Flex, Typography } from 'antd'; +import { isNil } from 'lodash'; import Link from 'next/link'; import { useMemo } from 'react'; @@ -11,7 +12,9 @@ import { SettingsScreen } from '@/enums/SettingsScreen'; import { useMultisig } from '@/hooks/useMultisig'; import { usePageState } from '@/hooks/usePageState'; import { useSettings } from '@/hooks/useSettings'; -import { useWalletContext } from '@/hooks/useWallet'; +import { useMasterWalletContext } from '@/hooks/useWallet'; +import { Address } from '@/types/Address'; +import { Optional } from '@/types/Util'; import { truncateAddress } from '@/utils/truncate'; import { CustomAlert } from '../Alert'; @@ -83,15 +86,34 @@ export const Settings = () => { }; const SettingsMain = () => { - const { wallets } = useWalletContext(); - const { backupSafeAddress } = useMultisig(); + const { masterEoa, masterSafes } = useMasterWalletContext(); + + const { owners } = useMultisig( + masterSafes?.[0], // TODO: all master safes should have the same address, but dirty implementation + ); + const { goto } = usePageState(); - const truncatedBackupSafeAddress: string | undefined = useMemo(() => { - if (backupSafeAddress) { - return truncateAddress(backupSafeAddress); + const masterSafeBackupAddresses = useMemo>(() => { + if (!owners) return; + if (!masterEoa) return; + + // TODO: handle edge cases where there are multiple owners due to middleware failure, or user interaction via safe.global + return owners.filter((owner) => owner !== masterEoa.address); + }, [owners, masterEoa]); + + const masterSafeBackupAddress = useMemo>(() => { + if (isNil(masterSafeBackupAddresses)) return; + if (!masterSafeBackupAddresses?.[0]) return; + + return masterSafeBackupAddresses[0]; + }, [masterSafeBackupAddresses]); + + const truncatedBackupSafeAddress: Optional = useMemo(() => { + if (masterSafeBackupAddress && masterSafeBackupAddress?.length) { + return truncateAddress(masterSafeBackupAddress); } - }, [backupSafeAddress]); + }, [masterSafeBackupAddress]); return ( { {/* Wallet backup */} Backup wallet - {backupSafeAddress ? ( + {masterSafeBackupAddress ? ( {truncatedBackupSafeAddress} {UNICODE_SYMBOLS.EXTERNAL_LINK} diff --git a/frontend/hooks/useMultisig.ts b/frontend/hooks/useMultisig.ts index 3793eb5e7..1e6df3a83 100644 --- a/frontend/hooks/useMultisig.ts +++ b/frontend/hooks/useMultisig.ts @@ -15,14 +15,17 @@ import { Address } from '@/types/Address'; * @returns multisig owners * @note extend with further multisig functions as needed */ -export const useMultisig = (safe: Safe) => { +export const useMultisig = (safe?: Safe) => { const { data: owners, isFetched: ownersIsFetched, isPending: ownersIsPending, - } = useQuery({ - queryKey: REACT_QUERY_KEYS.MULTISIG_GET_OWNERS_KEY(safe), + } = useQuery({ + queryKey: safe ? REACT_QUERY_KEYS.MULTISIG_GET_OWNERS_KEY(safe) : [], queryFn: async () => { + if (!safe) { + return null; + } const contract = new Contract( safe.address, GNOSIS_SAFE_ABI, From f6c75d9ee27dba0ae571a2aa902f37898fa3f413 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 17:27:11 +0000 Subject: [PATCH 330/463] feat: refactor logging hooks by removing deprecated useLogs and introducing a new implementation for better clarity and functionality --- .../Pages/HelpAndSupportPage/index.tsx | 2 +- frontend/hooks/backup/useLogs.ts | 103 -------------- frontend/hooks/useLogs.ts | 134 ++++++++++++++++++ frontend/hooks/useMultisig.ts | 6 +- 4 files changed, 139 insertions(+), 106 deletions(-) delete mode 100644 frontend/hooks/backup/useLogs.ts create mode 100644 frontend/hooks/useLogs.ts diff --git a/frontend/components/Pages/HelpAndSupportPage/index.tsx b/frontend/components/Pages/HelpAndSupportPage/index.tsx index 041f4f490..4e721e047 100644 --- a/frontend/components/Pages/HelpAndSupportPage/index.tsx +++ b/frontend/components/Pages/HelpAndSupportPage/index.tsx @@ -5,8 +5,8 @@ import { useCallback, useEffect, useState } from 'react'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { FAQ_URL, SUPPORT_URL } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; -import { useLogs } from '@/hooks/backup/useLogs'; import { useElectronApi } from '@/hooks/useElectronApi'; +import { useLogs } from '@/hooks/useLogs'; import { usePageState } from '@/hooks/usePageState'; import { CardTitle } from '../../Card/CardTitle'; diff --git a/frontend/hooks/backup/useLogs.ts b/frontend/hooks/backup/useLogs.ts deleted file mode 100644 index ccc7dee46..000000000 --- a/frontend/hooks/backup/useLogs.ts +++ /dev/null @@ -1,103 +0,0 @@ -// TODO: reintroduce, low prio for refactor - -// import { useQueryClient } from '@tanstack/react-query'; -// import { useMemo } from 'react'; - -// import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; - -// import { useBalanceContext } from './useBalanceContext'; -// import { useMultisig } from './useMultisig'; -// import { useServices } from './useServices'; -// import { useStore } from './useStore'; -// import { useMasterWalletContext } from './useWallet'; - -// const useAddressesLogs = () => { -// const { wallets, masterEoaAddress, masterSafeAddress } = useMasterWalletContext(); - -// const { backupSafeAddress, masterSafeOwners } = useMultisig(); - -// return { -// isLoaded: wallets?.length !== 0 && !!masterSafeOwners, -// data: [ -// { backupSafeAddress: backupSafeAddress ?? 'undefined' }, -// { masterSafeAddress: masterSafeAddress ?? 'undefined' }, -// { masterEoaAddress: masterEoaAddress ?? 'undefined' }, -// { masterSafeOwners: masterSafeOwners ?? 'undefined' }, -// ], -// }; -// }; - -// const useBalancesLogs = () => { -// const { -// isBalanceLoaded, -// totalEthBalance, -// totalOlasBalance, -// wallets, -// walletBalances, -// totalOlasStakedBalance, -// } = useBalanceContext(); - -// return { -// isLoaded: isBalanceLoaded, -// data: [ -// { wallets: wallets ?? 'undefined' }, -// { walletBalances: walletBalances ?? 'undefined' }, -// { totalOlasStakedBalance: totalOlasStakedBalance ?? 'undefined' }, -// { totalEthBalance: totalEthBalance ?? 'undefined' }, -// { totalOlasBalance: totalOlasBalance ?? 'undefined' }, -// ], -// }; -// }; - -// const useServicesLogs = () => { -// const { services, isFetched: isLoaded } = useServices(); -// const { getQueryData } = useQueryClient(); - -// return { -// isLoaded: isLoaded, -// data: { -// services: -// services?.map((item) => ({ -// ...item, -// keys: item.keys.map((key) => key.address), -// deploymentStatus: getQueryData([ -// REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY( -// item.service_config_id, -// ), -// item.service_config_id, -// ]), -// })) ?? 'undefined', -// }, -// }; -// }; - -// export const useLogs = () => { -// const { storeState } = useStore(); - -// const { isLoaded: isServicesLoaded, data: services } = useServicesLogs(); -// const { isLoaded: isBalancesLoaded, data: balances } = useBalancesLogs(); -// const { isLoaded: isAddressesLoaded, data: addresses } = useAddressesLogs(); - -// const logs = useMemo(() => { -// if (isServicesLoaded && isBalancesLoaded && isAddressesLoaded) { -// return { -// store: storeState, -// debugData: { -// services, -// addresses, -// balances, -// }, -// }; -// } -// }, [ -// addresses, -// balances, -// isAddressesLoaded, -// isBalancesLoaded, -// isServicesLoaded, -// services, -// storeState, -// ]); - -// return logs; -// }; diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts new file mode 100644 index 000000000..20311d6fc --- /dev/null +++ b/frontend/hooks/useLogs.ts @@ -0,0 +1,134 @@ +import { useQueryClient } from '@tanstack/react-query'; +import { useMemo } from 'react'; + +import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { ChainId } from '@/enums/Chain'; +import { Eoa, WalletType } from '@/enums/Wallet'; +import { Address } from '@/types/Address'; +import { Optional } from '@/types/Util'; + +import { useBalanceContext } from './useBalanceContext'; +import { useMultisigs } from './useMultisig'; +import { useServices } from './useServices'; +import { useStore } from './useStore'; +import { useMasterWalletContext } from './useWallet'; + +const useAddressesLogs = () => { + const { + masterSafes, + masterEoa, + isFetching: masterWalletsIsFetching, + } = useMasterWalletContext(); + + const { owners: allMasterSafeOwners, ownersIsPending } = + useMultisigs(masterSafes); + + const backupEoas = useMemo>(() => { + if (!masterEoa) return; + if (!allMasterSafeOwners) return; + + const result = allMasterSafeOwners + .map((owners) => + owners.owners + .filter((owner): owner is Address => owner !== masterEoa.address) + .map((owner) => ({ + address: owner, + type: WalletType.EOA, + safeAddress: owners.safeAddress, + chainId: owners.chainId, + })), + ) + .flat(); + + return result; + }, [allMasterSafeOwners, masterEoa]); + + return { + isLoaded: masterWalletsIsFetching && ownersIsPending, + data: [ + { masterEoa: masterEoa ?? 'undefined' }, + { + masterSafes: + masterSafes?.find((safe) => safe.chainId === ChainId.Gnosis) ?? + 'undefined', + }, + { masterSafeBackups: backupEoas ?? 'undefined' }, + ], + }; +}; + +const useBalancesLogs = () => { + const { masterWallets } = useMasterWalletContext(); + + const { + isLoaded: isBalanceLoaded, + totalEthBalance, + totalOlasBalance, + walletBalances, + totalStakedOlasBalance: totalOlasStakedBalance, + } = useBalanceContext(); + + return { + isLoaded: isBalanceLoaded, + data: [ + { masterWallets: masterWallets ?? 'undefined' }, + { walletBalances: walletBalances ?? 'undefined' }, + { totalOlasStakedBalance: totalOlasStakedBalance ?? 'undefined' }, + { totalEthBalance: totalEthBalance ?? 'undefined' }, + { totalOlasBalance: totalOlasBalance ?? 'undefined' }, + ], + }; +}; + +const useServicesLogs = () => { + const { services, isFetched: isLoaded } = useServices(); + const { getQueryData } = useQueryClient(); + + return { + isLoaded: isLoaded, + data: { + services: + services?.map((item) => ({ + ...item, + keys: item.keys.map((key) => key.address), + deploymentStatus: getQueryData([ + REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY( + item.service_config_id, + ), + item.service_config_id, + ]), + })) ?? 'undefined', + }, + }; +}; + +export const useLogs = () => { + const { storeState } = useStore(); + + const { isLoaded: isServicesLoaded, data: services } = useServicesLogs(); + const { isLoaded: isBalancesLoaded, data: balances } = useBalancesLogs(); + const { isLoaded: isAddressesLoaded, data: addresses } = useAddressesLogs(); + + const logs = useMemo(() => { + if (isServicesLoaded && isBalancesLoaded && isAddressesLoaded) { + return { + store: storeState, + debugData: { + services, + addresses, + balances, + }, + }; + } + }, [ + addresses, + balances, + isAddressesLoaded, + isBalancesLoaded, + isServicesLoaded, + services, + storeState, + ]); + + return logs; +}; diff --git a/frontend/hooks/useMultisig.ts b/frontend/hooks/useMultisig.ts index 1e6df3a83..9cd930bf1 100644 --- a/frontend/hooks/useMultisig.ts +++ b/frontend/hooks/useMultisig.ts @@ -1,6 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { Contract } from 'ethers'; import { Contract as MulticallContract, ContractCall } from 'ethers-multicall'; +import { isEmpty } from 'lodash'; import { GNOSIS_SAFE_ABI } from '@/abis/gnosisSafe'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; @@ -42,13 +43,13 @@ export const useMultisig = (safe?: Safe) => { /** * Hook to fetch from an array of multisigs */ -export const useMultisigs = (safes: Safe[]) => { +export const useMultisigs = (safes?: Safe[]) => { const { data: owners, isFetched: ownersIsFetched, isPending: ownersIsPending, } = useQuery<{ safeAddress: string; chainId: number; owners: string[] }[]>({ - queryKey: REACT_QUERY_KEYS.MULTISIGS_GET_OWNERS_KEY(safes), + queryKey: safes ? REACT_QUERY_KEYS.MULTISIGS_GET_OWNERS_KEY(safes) : [], queryFn: async (): Promise< { safeAddress: string; @@ -56,6 +57,7 @@ export const useMultisigs = (safes: Safe[]) => { owners: string[]; }[] > => { + if (!safes || isEmpty(safes)) return []; const results: { [chainId: number]: { safeAddress: string; From 69601fc84fc9c62e0aaf2edb2397e389c3a7c2b6 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 21 Nov 2024 18:45:23 +0100 Subject: [PATCH 331/463] feat: update safes multiple chains --- operate/cli.py | 68 ++++++++++++++++++++++++++++++---------- operate/wallet/master.py | 18 ++++++++--- 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/operate/cli.py b/operate/cli.py index ea1a3b407..4b8be1604 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -516,7 +516,7 @@ async def _create_safe(request: Request) -> t.List[t.Dict]: safes = t.cast(t.Dict[Chain, str], wallet.safes) wallet.create_safe( # pylint: disable=no-member chain=chain, - backup_owner=data.get("backup_owner"), + backup_owner=data.get("backup_owner"), ) wallet.transfer( to=t.cast(str, safes.get(chain)), @@ -552,7 +552,9 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: manager = operate.wallet_manager if not manager.exists(ledger_type=ledger_type): return JSONResponse( - content={"error": f"Wallet does not exist for chain {chain}"} + content={ + "error": f"A wallet of type {ledger_type} does not exist for chain {chain}." + } ) # mint the safes @@ -568,7 +570,7 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: safes = t.cast(t.Dict[Chain, str], wallet.safes) wallet.create_safe( # pylint: disable=no-member chain=chain, - owner=data.get("owner"), + owner=data.get("backup_owner"), ) wallet.transfer( to=t.cast(str, safes.get(chain)), @@ -577,7 +579,7 @@ async def _create_safes(request: Request) -> t.List[t.Dict]: from_safe=False, ) - return JSONResponse(content={"safes": safes, "message": "Safes created!"}) + return JSONResponse(content={"safes": safes, "message": "Safes created."}) @app.put("/api/wallet/safe") @with_retries @@ -586,29 +588,63 @@ async def _update_safe(request: Request) -> t.List[t.Dict]: # TODO: Extract login check as decorator if operate.user_account is None: return JSONResponse( - content={"error": "Cannot create safe; User account does not exist!"}, + content={"error": "Cannot update safe; User account does not exist!"}, status_code=400, ) if operate.password is None: return JSONResponse( - content={"error": "You need to login before updating a safe"}, + content={"error": "You need to login before updating a safe."}, status_code=401, ) - data = await request.json() - chain = Chain(data["chain"]) - ledger_type = chain.ledger_type manager = operate.wallet_manager - if not manager.exists(ledger_type=ledger_type): - return JSONResponse(content={"error": "Wallet does not exist"}) + data = await request.json() - wallet = manager.load(ledger_type=ledger_type) - wallet.update_backup_owner( - chain=chain, - backup_owner=data.get("backup_owner"), + chains = [] + if "chain" in data: + if "chains" in data: + return JSONResponse( + content={ + "error": "You cannot specify 'chain' and 'chains' in the same request." + }, + status_code=401, + ) + chains = [Chain[data["chain"]]] + elif "chains" in data: + chains = [Chain(chain_str) for chain_str in data["chains"]] + + # check that all chains are supported + for chain in chains: + ledger_type = chain.ledger_type + if not manager.exists(ledger_type=ledger_type): + return JSONResponse( + content={ + "error": f"A wallet of type {ledger_type} does not exist for chain {chain}." + } + ) + + # update backup owners + updated_safes = {} + for chain in chains: + ledger_type = chain.ledger_type + wallet = manager.load(ledger_type=ledger_type) + updated = wallet.update_backup_owner( + chain=chain, + backup_owner=data.get("backup_owner"), + ) + if updated: + updated_safes[chain.value] = wallet.safes[chain] + + if not updated_safes: + return JSONResponse(content={"message": "No safes were updated."}) + + return JSONResponse( + content={ + "updated_safes": updated_safes, + "message": "Safe backup owners updated.", + } ) - return JSONResponse(content=wallet.json) @app.get("/api/v2/services") @with_retries diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 9e6a856f1..af83319e9 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -44,7 +44,7 @@ from operate.resource import LocalResource from operate.utils.gnosis import add_owner from operate.utils.gnosis import create_safe as create_gnosis_safe -from operate.utils.gnosis import get_owners, swap_owner +from operate.utils.gnosis import get_owners, remove_owner, swap_owner from operate.utils.gnosis import transfer as transfer_from_safe from operate.utils.gnosis import transfer_erc20_from_safe @@ -141,7 +141,7 @@ def update_backup_owner( chain: Chain, backup_owner: t.Optional[str] = None, rpc: t.Optional[str] = None, - ) -> None: + ) -> bool: """Update backup owner.""" raise NotImplementedError() @@ -337,7 +337,7 @@ def update_backup_owner( chain: Chain, backup_owner: t.Optional[str] = None, rpc: t.Optional[str] = None, - ) -> None: + ) -> bool: """Adds a backup owner if not present, or updates it by the provided backup owner. Setting a None backup owner will remove the current one, if any.""" ledger_api = self.ledger_api(chain=chain, rpc=rpc) if chain not in self.safes: # type: ignore @@ -346,7 +346,9 @@ def update_backup_owner( owners = get_owners(ledger_api=ledger_api, safe=safe) if len(owners) > 2: - raise RuntimeError(f"Safe {safe} on chain {chain} has more than 2 owners: {owners}.") + raise RuntimeError( + f"Safe {safe} on chain {chain} has more than 2 owners: {owners}." + ) if backup_owner == safe: raise ValueError("The Safe address cannot be set as the Safe backup owner.") @@ -360,7 +362,7 @@ def update_backup_owner( old_backup_owner = owners[0] if owners else None if old_backup_owner == backup_owner: - return + return False if not old_backup_owner and backup_owner: add_owner( @@ -369,6 +371,7 @@ def update_backup_owner( owner=backup_owner, crypto=self.crypto, ) + return True elif old_backup_owner and not backup_owner: remove_owner( ledger_api=ledger_api, @@ -377,6 +380,7 @@ def update_backup_owner( crypto=self.crypto, threshold=1, ) + return True elif old_backup_owner and backup_owner: swap_owner( ledger_api=ledger_api, @@ -385,6 +389,10 @@ def update_backup_owner( new_owner=backup_owner, crypto=self.crypto, ) + return True + + return False + @classmethod def load(cls, path: Path) -> "EthereumMasterWallet": """Load master wallet.""" From 7e1ba4612464534a4596b00ebdc59bb19971aea1 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 21 Nov 2024 18:51:05 +0100 Subject: [PATCH 332/463] fix: linters --- operate/wallet/master.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/operate/wallet/master.py b/operate/wallet/master.py index af83319e9..17664103e 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -372,7 +372,7 @@ def update_backup_owner( crypto=self.crypto, ) return True - elif old_backup_owner and not backup_owner: + if old_backup_owner and not backup_owner: remove_owner( ledger_api=ledger_api, safe=safe, @@ -381,7 +381,7 @@ def update_backup_owner( threshold=1, ) return True - elif old_backup_owner and backup_owner: + if old_backup_owner and backup_owner: swap_owner( ledger_api=ledger_api, safe=safe, From 5c232ab4c3b35d43e830e60c7bf4d3f64e7da3d4 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Thu, 21 Nov 2024 18:54:30 +0100 Subject: [PATCH 333/463] chore: update api --- api.md | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/api.md b/api.md index 7bcaec3e9..baead9f81 100644 --- a/api.md +++ b/api.md @@ -244,6 +244,64 @@ Creates a Gnosis safe for given chain type. } ``` +
+ +
+ Response + +- If Gnosis safe creation is successful: + + ```json + { + "address": "0xaaFd5cb31A611C5e5aa65ea8c6226EB4328175E3", + "safe_chains": [ + 2 + ], + "ledger_type": 0, + "safes": { + "2": "0xe56fb574ce2C66008d5c4C09980c4f36Ab81ff22" + }, + "safe_nonce": 110558881674480320952254000342160989674913430251157716140571305138121962898821 + } + ``` + +- If Gnosis safe creation is not successful: + + ```json + { + "error": "Error message", + "traceback": "Traceback message" + } + ``` + +
+ +--- + +### `PUT /api/wallet/safe` + +Updtes a Gnosis safe for given chain type. + +
+ Request + +```js +{ + "chain": Chain, + "backup_owner": "0x650e83Bc808B8f405A9aF7CF68644cc817e084A6" +} +``` + +or + +```js +{ + "chains": ["chain1", "chain2", ...], + "backup_owner": "0x650e83Bc808B8f405A9aF7CF68644cc817e084A6" +} +``` + +
From e6269acade041e2baf35f25cf5d3ca00a1d1b133 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 18:00:38 +0000 Subject: [PATCH 334/463] refactor: update YourWalletPage to use updated types, contexts, hooks --- frontend/components/YourWalletPage/index.tsx | 113 +++++++++++++++---- 1 file changed, 88 insertions(+), 25 deletions(-) diff --git a/frontend/components/YourWalletPage/index.tsx b/frontend/components/YourWalletPage/index.tsx index e2486f04b..8a6a1b2ff 100644 --- a/frontend/components/YourWalletPage/index.tsx +++ b/frontend/components/YourWalletPage/index.tsx @@ -1,16 +1,28 @@ import { CloseOutlined } from '@ant-design/icons'; -import { Button, ConfigProvider, Flex, ThemeConfig, Typography } from 'antd'; +import { + Button, + ConfigProvider, + Flex, + Skeleton, + ThemeConfig, + Typography, +} from 'antd'; +import { isEmpty, isNil } from 'lodash'; import { useMemo } from 'react'; import { AddressLink } from '@/components/AddressLink'; import { CardTitle } from '@/components/Card/CardTitle'; import { InfoBreakdownList } from '@/components/InfoBreakdown'; import { CardFlex } from '@/components/styled/CardFlex'; +import { getNativeTokenSymbol } from '@/config/tokens'; +import { ChainId } from '@/enums/Chain'; import { Pages } from '@/enums/Pages'; +import { TokenSymbol } from '@/enums/Token'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { usePageState } from '@/hooks/usePageState'; -import { useServices } from '@/hooks/useServices'; -import { useWallet } from '@/hooks/useWallet'; +import { useMasterWalletContext } from '@/hooks/useWallet'; +import { type Address } from '@/types/Address'; +import { Optional } from '@/types/Util'; import { balanceFormat } from '@/utils/numberFormatters'; import { Container, infoBreakdownParentStyle } from './styles'; @@ -25,10 +37,15 @@ const yourWalletTheme: ThemeConfig = { }, }; -const YourWalletTitle = () => ; +const YourWalletTitle = () => ; const Address = () => { - const { masterSafeAddress } = useWallet(); + const { masterSafes } = useMasterWalletContext(); + + if (!masterSafes) return ; + if (isEmpty(masterSafes)) return null; + + const masterSafeAddress = masterSafes[0].address; // TODO: handle multiple safes in future return ( @@ -48,29 +65,37 @@ const Address = () => { }; const OlasBalance = () => { - const { masterSafeBalance: safeBalance, totalOlasStakedBalance } = - useBalanceContext(); + const { masterSafes } = useMasterWalletContext(); + const { walletBalances, totalStakedOlasBalance } = useBalanceContext(); + + const masterSafeOlasBalance: number = walletBalances + ?.filter((balance) => balance.symbol === TokenSymbol.OLAS) + .reduce((acc, balance) => acc + balance.balance, 0); + const olasBalances = useMemo(() => { return [ { title: 'Available', - value: balanceFormat(safeBalance?.OLAS ?? 0, 2), + value: balanceFormat(masterSafeOlasBalance ?? 0, 2), }, { title: 'Staked', - value: balanceFormat(totalOlasStakedBalance ?? 0, 2), + value: balanceFormat(totalStakedOlasBalance ?? 0, 2), }, ]; - }, [safeBalance?.OLAS, totalOlasStakedBalance]); + }, [masterSafeOlasBalance, totalStakedOlasBalance]); + + if (!masterSafes) return ; + if (isEmpty(masterSafes)) return null; return ( - OLAS + {TokenSymbol.OLAS} ({ left: item.title, leftClassName: 'text-light', - right: `${item.value} OLAS`, + right: `${item.value} ${TokenSymbol.OLAS}`, }))} parentStyle={infoBreakdownParentStyle} /> @@ -78,17 +103,38 @@ const OlasBalance = () => { ); }; -const XdaiBalance = () => { - const { masterSafeBalance: safeBalance } = useBalanceContext(); +const MasterSafeNativeBalance = () => { + const { masterSafes, masterEoa } = useMasterWalletContext(); + const { walletBalances } = useBalanceContext(); + + const masterSafeNativeBalance: Optional = useMemo(() => { + if (isNil(masterSafes)) return; + if (isNil(walletBalances)) return; + + if (isEmpty(masterSafes)) return 0; + if (isEmpty(walletBalances)) return 0; + + const masterSafe = masterSafes[0]; // TODO: handle multiple safes in future + + return walletBalances + .filter( + ({ walletAddress }) => + walletAddress === masterSafe.address || // TODO: handle multiple safes in future + walletAddress === masterEoa?.address, + ) + .reduce((acc, balance) => acc + balance.balance, 0); + }, [masterEoa?.address, masterSafes, walletBalances]); + + const nativeTokenSymbol = getNativeTokenSymbol(ChainId.Gnosis); return ( XDAI, + left: {getNativeTokenSymbol(ChainId.Gnosis)}, leftClassName: 'text-light', - right: `${balanceFormat(safeBalance?.ETH, 2)} XDAI`, + right: `${balanceFormat(masterSafeNativeBalance, 2)} ${nativeTokenSymbol}`, }, ]} parentStyle={infoBreakdownParentStyle} @@ -97,9 +143,27 @@ const XdaiBalance = () => { ); }; -const Signer = () => { - const { masterEoaAddress } = useWallet(); - const { masterEoaBalance: eoaBalance } = useBalanceContext(); +const MasterEoaSignerNativeBalance = () => { + const { masterEoa } = useMasterWalletContext(); + const { walletBalances } = useBalanceContext(); + + const masterEoaBalance = useMemo(() => { + if (isNil(masterEoa)) return; + if (isNil(walletBalances)) return; + + return walletBalances + .filter( + ( + { walletAddress, isNative }, // TODO: support chainId grouping, for multi-agent + ) => walletAddress === masterEoa.address && isNative, + ) + .reduce((acc, balance) => acc + balance.balance, 0); + }, [masterEoa, walletBalances]); + + const nativeTokenSymbol = useMemo( + () => getNativeTokenSymbol(ChainId.Gnosis), + [], + ); // TODO: support multi chain return ( @@ -109,11 +173,11 @@ const Signer = () => { left: ( ), leftClassName: 'text-light', - right: `${balanceFormat(eoaBalance?.ETH, 2)} XDAI`, + right: `${balanceFormat(masterEoaBalance, 2)} ${nativeTokenSymbol}`, }, ]} parentStyle={infoBreakdownParentStyle} @@ -124,7 +188,6 @@ const Signer = () => { export const YourWalletPage = () => { const { goto } = usePageState(); - const { service } = useServices(); return ( @@ -142,9 +205,9 @@ export const YourWalletPage = () => {
- - - {service && } + + + From 2af6dc125573764aede389599dff55ec258c8b11 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 18:04:43 +0000 Subject: [PATCH 335/463] refactor: specify type for masterEoaBalance in YourWalletPage component --- frontend/components/YourWalletPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/YourWalletPage/index.tsx b/frontend/components/YourWalletPage/index.tsx index 8a6a1b2ff..2b67d6cf3 100644 --- a/frontend/components/YourWalletPage/index.tsx +++ b/frontend/components/YourWalletPage/index.tsx @@ -147,7 +147,7 @@ const MasterEoaSignerNativeBalance = () => { const { masterEoa } = useMasterWalletContext(); const { walletBalances } = useBalanceContext(); - const masterEoaBalance = useMemo(() => { + const masterEoaBalance: Optional = useMemo(() => { if (isNil(masterEoa)) return; if (isNil(walletBalances)) return; From 2ae151a166162410f3125987ed635b270d12bfc5 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 18:55:35 +0000 Subject: [PATCH 336/463] fix: review comments --- frontend/components/YourWalletPage/index.tsx | 23 +++++++++++--------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/frontend/components/YourWalletPage/index.tsx b/frontend/components/YourWalletPage/index.tsx index 2b67d6cf3..d63aa58c4 100644 --- a/frontend/components/YourWalletPage/index.tsx +++ b/frontend/components/YourWalletPage/index.tsx @@ -18,7 +18,10 @@ import { getNativeTokenSymbol } from '@/config/tokens'; import { ChainId } from '@/enums/Chain'; import { Pages } from '@/enums/Pages'; import { TokenSymbol } from '@/enums/Token'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { + useBalanceContext, + useMasterBalances, +} from '@/hooks/useBalanceContext'; import { usePageState } from '@/hooks/usePageState'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { type Address } from '@/types/Address'; @@ -105,25 +108,25 @@ const OlasBalance = () => { const MasterSafeNativeBalance = () => { const { masterSafes, masterEoa } = useMasterWalletContext(); - const { walletBalances } = useBalanceContext(); + const { masterWalletBalances } = useMasterBalances(); const masterSafeNativeBalance: Optional = useMemo(() => { if (isNil(masterSafes)) return; - if (isNil(walletBalances)) return; + if (isNil(masterWalletBalances)) return; if (isEmpty(masterSafes)) return 0; - if (isEmpty(walletBalances)) return 0; + if (isEmpty(masterWalletBalances)) return 0; const masterSafe = masterSafes[0]; // TODO: handle multiple safes in future - return walletBalances + return masterWalletBalances .filter( ({ walletAddress }) => walletAddress === masterSafe.address || // TODO: handle multiple safes in future walletAddress === masterEoa?.address, ) .reduce((acc, balance) => acc + balance.balance, 0); - }, [masterEoa?.address, masterSafes, walletBalances]); + }, [masterEoa?.address, masterSafes, masterWalletBalances]); const nativeTokenSymbol = getNativeTokenSymbol(ChainId.Gnosis); @@ -145,20 +148,20 @@ const MasterSafeNativeBalance = () => { const MasterEoaSignerNativeBalance = () => { const { masterEoa } = useMasterWalletContext(); - const { walletBalances } = useBalanceContext(); + const { masterWalletBalances } = useMasterBalances(); const masterEoaBalance: Optional = useMemo(() => { if (isNil(masterEoa)) return; - if (isNil(walletBalances)) return; + if (isNil(masterWalletBalances)) return; - return walletBalances + return masterWalletBalances .filter( ( { walletAddress, isNative }, // TODO: support chainId grouping, for multi-agent ) => walletAddress === masterEoa.address && isNative, ) .reduce((acc, balance) => acc + balance.balance, 0); - }, [masterEoa, walletBalances]); + }, [masterEoa, masterWalletBalances]); const nativeTokenSymbol = useMemo( () => getNativeTokenSymbol(ChainId.Gnosis), From 4c80e728cff3a732b7c02394e877542dbba97ebe Mon Sep 17 00:00:00 2001 From: Mohan Date: Fri, 22 Nov 2024 01:51:48 +0530 Subject: [PATCH 337/463] feat: refactor onboarding (#478) * feat: enhance StakingContractSection to use selected service's chain ID for contract details link * feat: update SetupWelcomeLogin to utilize selected service's chain ID for master safe and balance checks * feat: refactor Setup components for improved chain support and address validation * feat: enhance SetupCreateSafe and SetupEoaFunding components for improved error handling and user feedback * fix: remove redundant text and clean up SetupRestore component layout * Update frontend/components/SetupPage/Create/SetupEoaFunding.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * Update frontend/components/SetupPage/Create/SetupEoaFunding.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * Update frontend/components/SetupPage/Create/SetupEoaFunding.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * feat: refactor Setup components to use master wallet balances and simplify logic --------- Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> --- frontend/components/Layout/TopBar.tsx | 4 +- .../StakingContractSection/index.tsx | 22 +- .../SetupPage/Create/SetupBackupSigner.tsx | 5 +- .../SetupPage/Create/SetupCreateSafe.tsx | 205 ++++++++++-------- .../SetupPage/Create/SetupEoaFunding.tsx | 93 ++++---- .../SetupPage/Create/SetupPassword.tsx | 3 +- .../SetupPage/Create/SetupSeedPhrase.tsx | 2 + .../components/SetupPage/SetupRestore.tsx | 3 + .../components/SetupPage/SetupWelcome.tsx | 37 +++- frontend/components/SetupPage/index.tsx | 6 +- frontend/config/mechs.ts | 9 +- frontend/config/stakingPrograms/index.ts | 14 +- frontend/constants/thresholds.ts | 10 +- frontend/pages/_app.tsx | 52 ++--- 14 files changed, 276 insertions(+), 189 deletions(-) diff --git a/frontend/components/Layout/TopBar.tsx b/frontend/components/Layout/TopBar.tsx index d552d243e..9428fc7f8 100644 --- a/frontend/components/Layout/TopBar.tsx +++ b/frontend/components/Layout/TopBar.tsx @@ -62,9 +62,7 @@ export const TopBar = () => { - - {`Pearl (Optimus) (alpha) ${envName ? `(${envName})` : ''}`.trim()} - + {`Pearl (alpha) ${envName ? `(${envName})` : ''}`.trim()} ); }; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index b23ffea35..51206d27f 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -1,13 +1,14 @@ import { Flex, Tag, theme, Typography } from 'antd'; import { useMemo } from 'react'; -import { MiddlewareChain } from '@/client'; import { CardSection } from '@/components/styled/CardSection'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { EXPLORER_URL } from '@/constants/urls'; import { StakingProgramId } from '@/enums/StakingProgram'; import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; +import { useServices } from '@/hooks/useServices'; import { useStakingProgram } from '@/hooks/useStakingProgram'; +import { Maybe } from '@/types/Util'; import { CantMigrateAlert } from './CantMigrateAlert'; import { MigrateButton } from './MigrateButton'; @@ -41,6 +42,7 @@ export const StakingContractSection = ({ activeStakingProgramMeta, activeStakingProgramAddress, } = useStakingProgram(); + const { selectedService } = useServices(); // /** // * Returns `true` if this stakingProgram is active, @@ -84,6 +86,9 @@ export const StakingContractSection = ({ ); }, [migrateValidation]); + const chainId: Maybe = + selectedService?.home_chain_id; + return ( <> - - View contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} - + + {chainId && ( + + View contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + )} {!migrateValidation.canMigrate && ( { const [form] = Form.useForm(); const handleFinish = (values: { 'backup-signer': string }) => { + // important to lowercase the address before check summing, invalid checksums will cause ethers to throw + // returns null if invalid, ethers type is incorrect... const checksummedAddress = getAddress( - // important to lowercase the address before checksumming, invalid checksums will cause ethers to throw values['backup-signer'].toLowerCase(), - ) as Address | null; // returns null if invalid, ethers type is incorrect... + ) as Address | null; // If the address is invalid, show an error message if (!checksummedAddress) { diff --git a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx index 2e16c158f..d063157d5 100644 --- a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx +++ b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx @@ -7,7 +7,6 @@ import { CardSection } from '@/components/styled/CardSection'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { SUPPORT_URL } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; -import { useMultisig } from '@/hooks/useMultisig'; import { usePageState } from '@/hooks/usePageState'; import { useSetup } from '@/hooks/useSetup'; import { useMasterWalletContext } from '@/hooks/useWallet'; @@ -22,25 +21,60 @@ const capitalizedMiddlewareChainNames = { [+MiddlewareChain.OPTIMISM]: 'Optimism', }; +const YouWillBeRedirected = ({ text }: { text: string }) => ( + <> + logo + + {text} + + + You will be redirected once the account is created. + + +); + +const CreationError = () => ( + <> + logo + + Error, please restart the app and try again. + + + If the issue persists,{' '} + + contact Olas community support {UNICODE_SYMBOLS.EXTERNAL_LINK} + + . + + +); + export const SetupCreateSafe = () => { const { goto } = usePageState(); - const { - updateWallets, - masterSafeAddressKeyExistsForChain, - masterSafeAddress, - } = useMasterWalletContext(); - const { updateMasterSafeOwners } = useMultisig(); + const { masterSafes, refetch: updateWallets } = useMasterWalletContext(); + // const { updateMasterSafeOwners } = useMultisig(); const { backupSigner } = useSetup(); + const masterSafeAddress = useMemo(() => { + if (!masterSafes) return; + return masterSafes[0]?.address; + }, [masterSafes]); + const [isCreatingSafe, setIsCreatingSafe] = useState(false); - const [optimismFailed, setOptimismFailed] = useState(false); - const [ethereumFailed, setEthereumFailed] = useState(false); - const [baseFailed, setBaseFailed] = useState(false); + const [gnosisFailed, setGnosisFailed] = useState(false); + // const [optimismFailed, setOptimismFailed] = useState(false); + // const [ethereumFailed, setEthereumFailed] = useState(false); + // const [baseFailed, setBaseFailed] = useState(false); - const [isOptimismSuccess, setIsOptimismSuccess] = useState(false); - const [isEthereumSuccess, setIsEthereumSuccess] = useState(false); - const [isBaseSuccess, setIsBaseSuccess] = useState(false); + const [isGnosisSuccess, setIsGnosisSuccess] = useState(false); + // const [isOptimismSuccess, setIsOptimismSuccess] = useState(false); + // const [isEthereumSuccess, setIsEthereumSuccess] = useState(false); + // const [isBaseSuccess, setIsBaseSuccess] = useState(false); const createSafeWithRetries = useCallback( async (middlewareChain: MiddlewareChain, retries: number) => { @@ -48,21 +82,28 @@ export const SetupCreateSafe = () => { // If we have retried too many times, set failed if (retries <= 0) { - if (middlewareChain === MiddlewareChain.OPTIMISM) { - setOptimismFailed(true); - setIsOptimismSuccess(false); - throw new Error('Failed to create safe on Ethereum'); - } - if (middlewareChain === MiddlewareChain.ETHEREUM) { - setEthereumFailed(true); - setIsEthereumSuccess(false); - throw new Error('Failed to create safe on Ethereum'); - } - if (middlewareChain === MiddlewareChain.BASE) { - setBaseFailed(true); - setIsBaseSuccess(false); + // if (middlewareChain === MiddlewareChain.OPTIMISM) { + // setOptimismFailed(true); + // setIsOptimismSuccess(false); + // throw new Error('Failed to create safe on Ethereum'); + // } + // if (middlewareChain === MiddlewareChain.ETHEREUM) { + // setEthereumFailed(true); + // setIsEthereumSuccess(false); + // throw new Error('Failed to create safe on Ethereum'); + // } + // if (middlewareChain === MiddlewareChain.BASE) { + // setBaseFailed(true); + // setIsBaseSuccess(false); + // throw new Error('Failed to create safe on Base'); + // } + + if (middlewareChain === MiddlewareChain.GNOSIS) { + setGnosisFailed(true); + setIsGnosisSuccess(false); throw new Error('Failed to create safe on Base'); } + throw new Error('Failed to create safe as chain is not supported'); } @@ -71,20 +112,23 @@ export const SetupCreateSafe = () => { .then(async () => { // Attempt wallet and master safe updates before proceeding try { - await updateWallets(); - await updateMasterSafeOwners(); + await updateWallets?.(); + // await updateMasterSafeOwners(); } catch (e) { console.error(e); } // Set states for successful creation setIsCreatingSafe(false); - setOptimismFailed(false); + // setOptimismFailed(false); + setGnosisFailed(false); }) .catch(async (e) => { console.error(e); + // Wait for 5 seconds before retrying await delayInSeconds(5); + // Retry const newRetries = retries - 1; if (newRetries <= 0) { @@ -95,7 +139,11 @@ export const SetupCreateSafe = () => { createSafeWithRetries(middlewareChain, newRetries); }); }, - [backupSigner, updateMasterSafeOwners, updateWallets], + [ + backupSigner, + // updateMasterSafeOwners, + updateWallets, + ], ); const creationStatusText = useMemo(() => { @@ -109,37 +157,47 @@ export const SetupCreateSafe = () => { /** * Avoid creating safes if any of the following conditions are met: */ - [optimismFailed, baseFailed, ethereumFailed].some((x) => x) || // any of the chains failed + [ + // optimismFailed, baseFailed, ethereumFailed + gnosisFailed, + ].some((x) => x) || // any of the chains failed isCreatingSafe //|| // already creating a safe // [isBaseSuccess, isEthereumSuccess, isOptimismSuccess].some((x) => !x) // any of the chains are not successful ) return; const chainsToCreateSafesFor = { - [MiddlewareChain.OPTIMISM]: masterSafeAddressKeyExistsForChain( - MiddlewareChain.OPTIMISM, - ), - [MiddlewareChain.ETHEREUM]: masterSafeAddressKeyExistsForChain( - MiddlewareChain.ETHEREUM, - ), - [MiddlewareChain.BASE]: masterSafeAddressKeyExistsForChain( - MiddlewareChain.BASE, - ), + // [MiddlewareChain.OPTIMISM]: masterSafeAddressKeyExistsForChain( + // MiddlewareChain.OPTIMISM, + // ), + // [MiddlewareChain.ETHEREUM]: masterSafeAddressKeyExistsForChain( + // MiddlewareChain.ETHEREUM, + // ), + // [MiddlewareChain.BASE]: masterSafeAddressKeyExistsForChain( + // MiddlewareChain.BASE, + // ), + [MiddlewareChain.GNOSIS]: !!masterSafeAddress, }; const safeCreationsRequired = Object.entries(chainsToCreateSafesFor).reduce( (acc, [chain, safeAddressAlreadyExists]) => { const middlewareChain = +chain as MiddlewareChain; if (safeAddressAlreadyExists) { + // switch (middlewareChain) { + // case MiddlewareChain.OPTIMISM: + // setIsOptimismSuccess(true); + // break; + // case MiddlewareChain.ETHEREUM: + // setIsEthereumSuccess(true); + // break; + // case MiddlewareChain.BASE: + // setIsBaseSuccess(true); + // break; + // } + switch (middlewareChain) { - case MiddlewareChain.OPTIMISM: - setIsOptimismSuccess(true); - break; - case MiddlewareChain.ETHEREUM: - setIsEthereumSuccess(true); - break; - case MiddlewareChain.BASE: - setIsBaseSuccess(true); + case MiddlewareChain.GNOSIS: + setIsGnosisSuccess(true); break; } return acc; @@ -169,14 +227,16 @@ export const SetupCreateSafe = () => { }, [ backupSigner, createSafeWithRetries, - optimismFailed, + masterSafeAddress, isCreatingSafe, - isBaseSuccess, - isEthereumSuccess, - isOptimismSuccess, - baseFailed, - ethereumFailed, - masterSafeAddressKeyExistsForChain, + // optimismFailed, + // isBaseSuccess, + // isEthereumSuccess, + // isOptimismSuccess, + // baseFailed, + // ethereumFailed, + isGnosisSuccess, + gnosisFailed, ]); useEffect(() => { @@ -193,39 +253,10 @@ export const SetupCreateSafe = () => { padding="80px 24px" gap={12} > - {optimismFailed ? ( - <> - logo - - Error, please restart the app and try again. - - - If the issue persists,{' '} - - contact Olas community support {UNICODE_SYMBOLS.EXTERNAL_LINK} - - . - - + {gnosisFailed ? ( + ) : ( - <> - logo - - {creationStatusText} - - - You will be redirected once the account is created. - - + )} diff --git a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx index 9b566ca37..f9042667d 100644 --- a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx +++ b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx @@ -1,7 +1,7 @@ import { CopyOutlined } from '@ant-design/icons'; import { Flex, message, Tooltip, Typography } from 'antd'; import { BigNumber, ethers } from 'ethers'; -import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import styled from 'styled-components'; import { useInterval } from 'usehooks-ts'; @@ -10,15 +10,14 @@ import { CustomAlert } from '@/components/Alert'; import { CardFlex } from '@/components/styled/CardFlex'; import { CardSection } from '@/components/styled/CardSection'; import { CHAIN_CONFIG } from '@/config/chains'; -import { - BASE_PROVIDER, - ETHEREUM_PROVIDER, - OPTIMISM_PROVIDER, -} from '@/constants/providers'; +import { PROVIDERS } from '@/constants/providers'; +import { NA } from '@/constants/symbols'; import { MIN_ETH_BALANCE_THRESHOLDS } from '@/constants/thresholds'; +import { ChainId } from '@/enums/Chain'; import { SetupScreen } from '@/enums/SetupScreen'; +import { useMasterBalances } from '@/hooks/useBalanceContext'; import { useSetup } from '@/hooks/useSetup'; -import { useWallet } from '@/hooks/useWallet'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { Address } from '@/types/Address'; import { copyToClipboard } from '@/utils/copyToClipboard'; import { delayInSeconds } from '@/utils/delay'; @@ -40,9 +39,18 @@ const AccountCreationCard = styled.div` const ICON_STYLE = { color: '#606F85' }; +const statusMessage = (isFunded?: boolean) => { + if (isFunded) { + return 'Funds have been received!'; + } else { + return 'Waiting for transaction'; + } +}; + type SetupEoaFundingWaitingProps = { chainName: string }; const SetupEoaFundingWaiting = ({ chainName }: SetupEoaFundingWaitingProps) => { - const { masterEoaAddress } = useWallet(); + const { masterEoa } = useMasterWalletContext(); + const masterEoaAddress = masterEoa?.address; return ( <> @@ -80,7 +88,7 @@ const SetupEoaFundingWaiting = ({ chainName }: SetupEoaFundingWaitingProps) => { - {`ETH: ${masterEoaAddress}`} + {`XDAI: ${masterEoaAddress || NA}`} {/* { const { goto } = useSetup(); - const statusMessage = useMemo(() => { - if (isFunded) { - return 'Funds have been received!'; - } else { - return 'Waiting for transaction'; - } - }, [isFunded]); - useEffect(() => { message.success(`${chainName} funds have been received!`); @@ -141,7 +141,7 @@ export const SetupEoaFundingForChain = ({ borderbottom={isFunded ? 'true' : 'false'} > - Status: {statusMessage} + Status: {statusMessage(isFunded)} {!isFunded && } @@ -149,29 +149,38 @@ export const SetupEoaFundingForChain = ({ ); }; +// TODO: chain independent const eoaFundingMap = { - [MiddlewareChain.OPTIMISM]: { - provider: OPTIMISM_PROVIDER, - chainConfig: CHAIN_CONFIG.OPTIMISM, - requiredEth: - MIN_ETH_BALANCE_THRESHOLDS[MiddlewareChain.OPTIMISM].safeCreation, - }, - [MiddlewareChain.ETHEREUM]: { - provider: ETHEREUM_PROVIDER, - chainConfig: CHAIN_CONFIG.ETHEREUM, - requiredEth: - MIN_ETH_BALANCE_THRESHOLDS[MiddlewareChain.ETHEREUM].safeCreation, - }, - [MiddlewareChain.BASE]: { - provider: BASE_PROVIDER, - chainConfig: CHAIN_CONFIG.BASE, - requiredEth: MIN_ETH_BALANCE_THRESHOLDS[MiddlewareChain.BASE].safeCreation, + // [MiddlewareChain.OPTIMISM]: { + // provider: OPTIMISM_PROVIDER, + // chainConfig: CHAIN_CONFIG.OPTIMISM, + // requiredEth: + // MIN_ETH_BALANCE_THRESHOLDS[MiddlewareChain.OPTIMISM].safeCreation, + // }, + // [MiddlewareChain.ETHEREUM]: { + // provider: ETHEREUM_PROVIDER, + // chainConfig: CHAIN_CONFIG.ETHEREUM, + // requiredEth: + // MIN_ETH_BALANCE_THRESHOLDS[MiddlewareChain.ETHEREUM].safeCreation, + // }, + // [MiddlewareChain.BASE]: { + // provider: BASE_PROVIDER, + // chainConfig: CHAIN_CONFIG.BASE, + // requiredEth: MIN_ETH_BALANCE_THRESHOLDS[MiddlewareChain.BASE].safeCreation, + // }, + [MiddlewareChain.GNOSIS]: { + provider: PROVIDERS[ChainId.Gnosis].provider, + chainConfig: CHAIN_CONFIG[ChainId.Gnosis], + requiredEth: MIN_ETH_BALANCE_THRESHOLDS[ChainId.Gnosis].safeCreation, }, }; export const SetupEoaFunding = () => { const { goto } = useSetup(); - const { masterEoaAddress } = useWallet(); + const { masterEoa } = useMasterWalletContext(); + const { masterWalletBalances } = useMasterBalances(); + const masterEoaAddress = masterEoa?.address; + const [currentChain, setCurrentChain] = useState( +Object.keys(eoaFundingMap)[0] as MiddlewareChain, ); @@ -225,6 +234,14 @@ export const SetupEoaFunding = () => { goto(SetupScreen.SetupCreateSafe); }, 5000); + const eoaBalance = masterWalletBalances?.find( + (balance) => balance.walletAddress === masterEoaAddress, + ); + const isFunded = + eoaBalance?.chainId === ChainId.Gnosis && + eoaBalance.balance >= + MIN_ETH_BALANCE_THRESHOLDS[ChainId.Gnosis].safeCreation; + return ( @@ -235,15 +252,15 @@ export const SetupEoaFunding = () => { The app needs these funds to create your account on-chain. - {/* - Status: {statusMessage} + Status: {statusMessage(isFunded)} - */} + { const [form] = Form.useForm<{ password: string; terms: boolean }>(); const [isLoading, setIsLoading] = useState(false); - const isTermsAccepted = Form.useWatch('terms', form); const handleCreateEoa = async ({ password }: { password: string }) => { @@ -26,7 +25,7 @@ export const SetupPassword = () => { setIsLoading(true); AccountService.createAccount(password) .then(() => AccountService.loginAccount(password)) - .then(() => WalletService.createEoa(MiddlewareChain.OPTIMISM)) + .then(() => WalletService.createEoa(MiddlewareChain.GNOSIS)) // TODO: chain independent .then(({ mnemonic }: { mnemonic: string[] }) => { setMnemonic(mnemonic); goto(SetupScreen.SetupSeedPhrase); diff --git a/frontend/components/SetupPage/Create/SetupSeedPhrase.tsx b/frontend/components/SetupPage/Create/SetupSeedPhrase.tsx index 46a8d1bca..dd8811f61 100644 --- a/frontend/components/SetupPage/Create/SetupSeedPhrase.tsx +++ b/frontend/components/SetupPage/Create/SetupSeedPhrase.tsx @@ -18,6 +18,7 @@ export const SetupSeedPhrase = () => { Back up seed phrase + Seed phrase is needed to regain access to your account if you forget @@ -33,6 +34,7 @@ export const SetupSeedPhrase = () => { ))} + + If you don’t have the seed phrase but added a backup wallet to your @@ -134,6 +136,7 @@ export const SetupRestoreViaSeed = () => { export const SetupRestoreSetPassword = () => { const { goto } = useSetup(); const [password, setPassword] = useState(''); + return ( { const { goto } = useSetup(); const { goto: gotoPage } = usePageState(); - const { masterSafeAddress, masterWallets: wallets } = - useMasterWalletContext(); - const { isBalanceLoaded, masterEoaBalance: eoaBalance } = useBalanceContext(); + const { selectedService } = useServices(); + const { + masterSafes, + masterWallets: wallets, + masterEoa, + } = useMasterWalletContext(); + const { isLoaded } = useBalanceContext(); + const { masterWalletBalances } = useMasterBalances(); + + const masterSafe = + masterSafes?.find( + (safe) => safe.chainId === selectedService?.home_chain_id, + ) ?? null; + const eoaBalanceEth = masterWalletBalances?.find( + (balance) => balance.walletAddress === masterEoa?.address, + ); const [isLoggingIn, setIsLoggingIn] = useState(false); const [canNavigate, setCanNavigate] = useState(false); @@ -157,11 +174,11 @@ export const SetupWelcomeLogin = () => { useEffect(() => { // Navigate only when wallets and balances are loaded // To check if some setup steps were missed - if (canNavigate && wallets?.length && isBalanceLoaded) { + if (canNavigate && wallets?.length && isLoaded) { setIsLoggingIn(false); - if (!eoaBalance?.ETH) { + if (!eoaBalanceEth) { goto(SetupScreen.SetupEoaFundingIncomplete); - } else if (!masterSafeAddress) { + } else if (!masterSafe?.address) { goto(SetupScreen.SetupCreateSafe); } else { gotoPage(Pages.Main); @@ -169,11 +186,11 @@ export const SetupWelcomeLogin = () => { } }, [ canNavigate, - eoaBalance?.ETH, + eoaBalanceEth, goto, gotoPage, - isBalanceLoaded, - masterSafeAddress, + isLoaded, + masterSafe?.address, wallets?.length, ]); diff --git a/frontend/components/SetupPage/index.tsx b/frontend/components/SetupPage/index.tsx index 412f4bc83..935ac2810 100644 --- a/frontend/components/SetupPage/index.tsx +++ b/frontend/components/SetupPage/index.tsx @@ -16,6 +16,10 @@ import { } from './SetupRestore'; import { SetupWelcome } from './SetupWelcome'; +const UnexpectedError = () => ( +
Something went wrong!
+); + export const Setup = () => { const { setupObject } = useContext(SetupContext); const setupScreen = useMemo(() => { @@ -45,7 +49,7 @@ export const Setup = () => { case SetupScreen.RestoreViaBackup: return ; default: - return <>Error; + return ; } }, [setupObject.state]); diff --git a/frontend/config/mechs.ts b/frontend/config/mechs.ts index 375171852..c55eb15c9 100644 --- a/frontend/config/mechs.ts +++ b/frontend/config/mechs.ts @@ -1,3 +1,4 @@ +import { JsonFragment } from '@ethersproject/abi'; import { Contract as MulticallContract } from 'ethers-multicall'; import { AGENT_MECH_ABI } from '@/abis/agentMech'; @@ -24,14 +25,18 @@ export const MECHS: Mechs = { name: 'Agent Mech', contract: new MulticallContract( '0x77af31De935740567Cf4fF1986D04B2c964A786a', - AGENT_MECH_ABI, + AGENT_MECH_ABI.filter( + (abi) => (abi as JsonFragment).type === 'function', + ) as JsonFragment[], ), }, [MechType.Marketplace]: { name: 'Mech Marketplace', contract: new MulticallContract( '0x4554fE75c1f5576c1d7F765B2A036c199Adae329', - MECH_MARKETPLACE_ABI, + MECH_MARKETPLACE_ABI.filter( + (abi) => (abi as JsonFragment).type === 'function', + ) as JsonFragment[], ), }, }, diff --git a/frontend/config/stakingPrograms/index.ts b/frontend/config/stakingPrograms/index.ts index 8c4be8c60..8c22a1921 100644 --- a/frontend/config/stakingPrograms/index.ts +++ b/frontend/config/stakingPrograms/index.ts @@ -10,10 +10,10 @@ import { GNOSIS_STAKING_PROGRAMS, GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES, } from './gnosis'; -import { - OPTIMISM_STAKING_PROGRAMS, - OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, -} from './optimism'; +// import { +// OPTIMISM_STAKING_PROGRAMS, +// OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, +// } from './optimism'; /** * Single non-chain specific staking program configuration @@ -40,19 +40,19 @@ export const STAKING_PROGRAMS: { [chainId: number | ChainId]: StakingProgramMap; } = { [ChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS, - [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS, + // [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS, }; export const STAKING_PROGRAM_ADDRESS: { [chainId: number | ChainId]: Record; } = { [ChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES, - [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, + // [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, }; export const INITIAL_DEFAULT_STAKING_PROGRAM_IDS: { [chainId: number | ChainId]: StakingProgramId; } = { [ChainId.Gnosis]: StakingProgramId.PearlBeta, - [ChainId.Optimism]: StakingProgramId.OptimusAlpha, + // [ChainId.Optimism]: StakingProgramId.OptimusAlpha, }; diff --git a/frontend/constants/thresholds.ts b/frontend/constants/thresholds.ts index 09d2b0c43..e85fa3086 100644 --- a/frontend/constants/thresholds.ts +++ b/frontend/constants/thresholds.ts @@ -1,13 +1,15 @@ import { ChainId } from '@/enums/Chain'; +// TODO + /** * @warning must be updated to be dynamic */ export const MIN_ETH_BALANCE_THRESHOLDS = { - // [Chain.GNOSIS]: { - // safeCreation: 1.5, - // safeAddSigner: 0.1, - // }, + [ChainId.Gnosis]: { + safeCreation: 1.5, + safeAddSigner: 0.1, + }, [ChainId.Optimism]: { safeCreation: 0.005, safeAddSigner: 0.005, diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 86d81156d..63ecbdf74 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -38,37 +38,37 @@ export default function App({ Component, pageProps }: AppProps) { - - - - - - - - - - - - {isMounted ? ( - + + + + + + + + + + + + + {isMounted ? ( - - ) : null} - - - - - - - - - - - + ) : null} + + + + + + + + + + + + From 023164bac402d131a192169ffffbf702893c9019 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Fri, 22 Nov 2024 10:45:27 +0400 Subject: [PATCH 338/463] refactor: add funds section --- .../MainPage/sections/AddFundsSection.tsx | 185 +++++++++--------- 1 file changed, 91 insertions(+), 94 deletions(-) diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index b7ab3dd87..d42925785 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -11,17 +11,15 @@ import { Tooltip, Typography, } from 'antd'; -import { BigNumber, Contract, ethers } from 'ethers'; import Link from 'next/link'; import { forwardRef, useCallback, useMemo, useRef, useState } from 'react'; import styled from 'styled-components'; -import { useInterval } from 'usehooks-ts'; -import { ERC20_BALANCE_OF_STRING_FRAGMENT } from '@/abis/erc20'; +import { CustomAlert } from '@/components/Alert'; import { CHAIN_CONFIG } from '@/config/chains'; -import { TOKEN_CONFIG } from '@/config/tokens'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { COW_SWAP_GNOSIS_XDAI_OLAS_URL } from '@/constants/urls'; +import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { copyToClipboard } from '@/utils/copyToClipboard'; import { delayInSeconds } from '@/utils/delay'; @@ -43,10 +41,10 @@ export const AddFundsSection = () => { const addFunds = useCallback(async () => { setIsAddFundsVisible(true); - await delayInSeconds(0.1); fundSectionRef?.current?.scrollIntoView({ behavior: 'smooth' }); }, []); + const closeAddFunds = useCallback(() => setIsAddFundsVisible(false), []); return ( @@ -77,21 +75,20 @@ export const AddFundsSection = () => { }; export const OpenAddFundsSection = forwardRef((_, ref) => { - const { masterSafeAddress } = useMasterWalletContext(); + const { selectedAgentConfig } = useServices(); + const { homeChainId } = selectedAgentConfig; + const { masterSafes } = useMasterWalletContext(); + const masterSafeAddress = useMemo( + () => + masterSafes?.find((wallet) => wallet.chainId === homeChainId)?.address, + [homeChainId, masterSafes], + ); const truncatedFundingAddress: string | undefined = useMemo( () => masterSafeAddress && truncateAddress(masterSafeAddress, 4), [masterSafeAddress], ); - const [ethEth, setethEth] = useState(0); - const [ethUsdc, setethUsdc] = useState(0); - - const [opEth, setopEth] = useState(0); - const [opOlas, setopOlas] = useState(0); - - const [baseEth, setbaseEth] = useState(0); - const handleCopyAddress = useCallback( () => masterSafeAddress && @@ -101,92 +98,87 @@ export const OpenAddFundsSection = forwardRef((_, ref) => { [masterSafeAddress], ); - useInterval(async () => { - if (!masterSafeAddress) return; - await Promise.allSettled([ - ETHEREUM_PROVIDER.getBalance(masterSafeAddress) - .then(ethers.utils.formatEther) - .then(Number) - .then(setethEth), - //USDC balance - new Contract( - TOKEN_CONFIG[CHAIN_CONFIG.ETHEREUM.chainId]['USDC'].address, - ERC20_BALANCE_OF_STRING_FRAGMENT, - ETHEREUM_PROVIDER, - ) - .balanceOf(masterSafeAddress) - .then((wei: BigNumber) => ethers.utils.formatUnits(wei, 6)) - .then(Number) - .then(setethUsdc), - OPTIMISM_PROVIDER.getBalance(masterSafeAddress) - .then(ethers.utils.formatEther) - .then(Number) - .then(setopEth), - new Contract( - TOKEN_CONFIG[CHAIN_CONFIG.OPTIMISM.chainId]['OLAS'].address, - ERC20_BALANCE_OF_STRING_FRAGMENT, - OPTIMISM_PROVIDER, - ) - .balanceOf(masterSafeAddress) - .then(ethers.utils.formatEther) - .then(Number) - .then(setopOlas), - BASE_PROVIDER.getBalance(masterSafeAddress) - .then(ethers.utils.formatEther) - .then(Number) - .then(setbaseEth), - ]); - }, 2000); + // const [ethEth, setethEth] = useState(0); + // const [ethUsdc, setethUsdc] = useState(0); + + // const [opEth, setopEth] = useState(0); + // const [opOlas, setopOlas] = useState(0); + + // const [baseEth, setbaseEth] = useState(0); + // useInterval(async () => { + // if (!masterSafeAddress) return; + // await Promise.allSettled([ + // ETHEREUM_PROVIDER.getBalance(masterSafeAddress) + // .then(ethers.utils.formatEther) + // .then(Number) + // .then(setethEth), + // //USDC balance + // new Contract( + // TOKEN_CONFIG[CHAIN_CONFIG.ETHEREUM.chainId]['USDC'].address, + // ERC20_BALANCE_OF_STRING_FRAGMENT, + // ETHEREUM_PROVIDER, + // ) + // .balanceOf(masterSafeAddress) + // .then((wei: BigNumber) => ethers.utils.formatUnits(wei, 6)) + // .then(Number) + // .then(setethUsdc), + // OPTIMISM_PROVIDER.getBalance(masterSafeAddress) + // .then(ethers.utils.formatEther) + // .then(Number) + // .then(setopEth), + // new Contract( + // TOKEN_CONFIG[CHAIN_CONFIG.OPTIMISM.chainId]['OLAS'].address, + // ERC20_BALANCE_OF_STRING_FRAGMENT, + // OPTIMISM_PROVIDER, + // ) + // .balanceOf(masterSafeAddress) + // .then(ethers.utils.formatEther) + // .then(Number) + // .then(setopOlas), + // BASE_PROVIDER.getBalance(masterSafeAddress) + // .then(ethers.utils.formatEther) + // .then(Number) + // .then(setbaseEth), + // ]); + // }, 2000); return ( - {/* */} - + -
-        {`
--- Master Safe Balances --
-Ethereum
-ETH ${ethEth}
-USDC ${ethUsdc}
-
-Optimism 
-ETH ${opEth} 
-OLAS ${opOlas}
-
-Base
-ETH ${baseEth}
-`}
-      
); }); OpenAddFundsSection.displayName = 'OpenAddFundsSection'; -// const AddFundsWarningAlertSection = () => ( -// -// -// -// Only send funds on {CHAINS.OPTIMISM.name}! -// -// -// You will lose any assets you send on other chains. -// -//
-// } -// /> -// -// ); +const AddFundsWarningAlertSection = () => { + const { selectedAgentConfig } = useServices(); + const { homeChainId } = selectedAgentConfig; + return ( + + + + Only send funds on {CHAIN_CONFIG[homeChainId].name} Chain! + + + You will lose any assets you send on other chains. + + + } + /> + + ); +}; const AddFundsAddressSection = ({ fundingAddress, @@ -224,11 +216,16 @@ const AddFundsAddressSection = ({ ); -const AddFundsGetTokensSection = () => ( - - - Get OLAS + {CHAIN_CONFIG.OPTIMISM.currency} on{' '} - {CHAIN_CONFIG.OPTIMISM.name} {UNICODE_SYMBOLS.EXTERNAL_LINK} - - -); +const AddFundsGetTokensSection = () => { + const { selectedAgentConfig } = useServices(); + const { homeChainId } = selectedAgentConfig; + + return ( + + + Get OLAS + {CHAIN_CONFIG[homeChainId].currency} on{' '} + {CHAIN_CONFIG[homeChainId].name} {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + ); +}; From f615fb562645d046eda8df09f04c61289695d66e Mon Sep 17 00:00:00 2001 From: Atatakai Date: Fri, 22 Nov 2024 10:49:52 +0400 Subject: [PATCH 339/463] refactor: remove commented code, add todo --- .../MainPage/sections/AddFundsSection.tsx | 52 +++---------------- 1 file changed, 7 insertions(+), 45 deletions(-) diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index d42925785..37f3f189a 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -98,50 +98,6 @@ export const OpenAddFundsSection = forwardRef((_, ref) => { [masterSafeAddress], ); - // const [ethEth, setethEth] = useState(0); - // const [ethUsdc, setethUsdc] = useState(0); - - // const [opEth, setopEth] = useState(0); - // const [opOlas, setopOlas] = useState(0); - - // const [baseEth, setbaseEth] = useState(0); - // useInterval(async () => { - // if (!masterSafeAddress) return; - // await Promise.allSettled([ - // ETHEREUM_PROVIDER.getBalance(masterSafeAddress) - // .then(ethers.utils.formatEther) - // .then(Number) - // .then(setethEth), - // //USDC balance - // new Contract( - // TOKEN_CONFIG[CHAIN_CONFIG.ETHEREUM.chainId]['USDC'].address, - // ERC20_BALANCE_OF_STRING_FRAGMENT, - // ETHEREUM_PROVIDER, - // ) - // .balanceOf(masterSafeAddress) - // .then((wei: BigNumber) => ethers.utils.formatUnits(wei, 6)) - // .then(Number) - // .then(setethUsdc), - // OPTIMISM_PROVIDER.getBalance(masterSafeAddress) - // .then(ethers.utils.formatEther) - // .then(Number) - // .then(setopEth), - // new Contract( - // TOKEN_CONFIG[CHAIN_CONFIG.OPTIMISM.chainId]['OLAS'].address, - // ERC20_BALANCE_OF_STRING_FRAGMENT, - // OPTIMISM_PROVIDER, - // ) - // .balanceOf(masterSafeAddress) - // .then(ethers.utils.formatEther) - // .then(Number) - // .then(setopOlas), - // BASE_PROVIDER.getBalance(masterSafeAddress) - // .then(ethers.utils.formatEther) - // .then(Number) - // .then(setbaseEth), - // ]); - // }, 2000); - return ( @@ -222,7 +178,13 @@ const AddFundsGetTokensSection = () => { return ( - + Get OLAS + {CHAIN_CONFIG[homeChainId].currency} on{' '} {CHAIN_CONFIG[homeChainId].name} {UNICODE_SYMBOLS.EXTERNAL_LINK} From ae81ebd0661ec0aba3dc52a18a4ce58b99d070b6 Mon Sep 17 00:00:00 2001 From: Mohan Date: Fri, 22 Nov 2024 13:40:06 +0530 Subject: [PATCH 340/463] feat: last transaction (#481) * feat: enhance StakingContractSection to use selected service's chain ID for contract details link * feat: update SetupWelcomeLogin to utilize selected service's chain ID for master safe and balance checks * feat: refactor Setup components for improved chain support and address validation * feat: enhance SetupCreateSafe and SetupEoaFunding components for improved error handling and user feedback * fix: remove redundant text and clean up SetupRestore component layout * Update frontend/components/SetupPage/Create/SetupEoaFunding.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * Update frontend/components/SetupPage/Create/SetupEoaFunding.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * Update frontend/components/SetupPage/Create/SetupEoaFunding.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * feat: refactor Setup components to use master wallet balances and simplify logic * refactor: simplify service configuration handling and remove unused useAddress hook --------- Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> --- .../header/AgentButton/AgentRunningButton.tsx | 14 +++++++------- .../MainPage/header/LastTransaction.tsx | 15 +++++++++------ frontend/hooks/backup/useAddress.ts | 17 ----------------- 3 files changed, 16 insertions(+), 30 deletions(-) delete mode 100644 frontend/hooks/backup/useAddress.ts diff --git a/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx index 569b01cb1..3b5626b36 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx @@ -34,12 +34,11 @@ export const AgentRunningButton = () => { const { selectedService, isFetched: isLoaded, setPaused } = useServices(); - const { service, setDeploymentStatus } = useService({ - serviceConfigId: - isLoaded && selectedService?.service_config_id - ? selectedService.service_config_id - : '', - }); + const serviceConfigId = + isLoaded && selectedService?.service_config_id + ? selectedService.service_config_id + : ''; + const { service, setDeploymentStatus } = useService({ serviceConfigId }); const handlePause = useCallback(async () => { if (!service) return; @@ -76,7 +75,8 @@ export const AgentRunningButton = () => { Agent is working )} - + + ); diff --git a/frontend/components/MainPage/header/LastTransaction.tsx b/frontend/components/MainPage/header/LastTransaction.tsx index b90859345..5ab251361 100644 --- a/frontend/components/MainPage/header/LastTransaction.tsx +++ b/frontend/components/MainPage/header/LastTransaction.tsx @@ -6,11 +6,12 @@ import { useInterval } from 'usehooks-ts'; import { MiddlewareChain } from '@/client'; import { ONE_MINUTE_INTERVAL } from '@/constants/intervals'; import { EXPLORER_URL } from '@/constants/urls'; -import { useAddress } from '@/hooks/useAddress'; import { usePageState } from '@/hooks/usePageState'; +import { useService } from '@/hooks/useService'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { getLatestTransaction } from '@/service/Ethers'; import { TransactionInfo } from '@/types/TransactionInfo'; +import { Optional } from '@/types/Util'; import { getTimeAgo } from '@/utils/time'; const { Text } = Typography; @@ -24,21 +25,23 @@ const Loader = styled(Skeleton.Input)` } `; +type LastTransactionProps = { serviceConfigId: Optional }; + /** * Displays the last transaction time and link to the transaction on explorer * by agent safe. */ -// TODO: loop over all supported chains -export const LastTransaction = () => { +export const LastTransaction = ({ serviceConfigId }: LastTransactionProps) => { const { isPageLoadedAndOneMinutePassed } = usePageState(); - const { multisigAddress } = useAddress(); const { activeStakingProgramMeta } = useStakingProgram(); + const { service } = useService({ serviceConfigId }); + const multisigAddress = + service?.chain_configs[service?.home_chain_id].chain_data.multisig; + const chainId = activeStakingProgramMeta?.chainId; const [isFetching, setIsFetching] = useState(true); const [transaction, setTransaction] = useState(null); - const chainId = activeStakingProgramMeta?.chainId; - const fetchTransaction = useCallback(async () => { if (!multisigAddress) return; if (!chainId) return; diff --git a/frontend/hooks/backup/useAddress.ts b/frontend/hooks/backup/useAddress.ts deleted file mode 100644 index 3be5c2626..000000000 --- a/frontend/hooks/backup/useAddress.ts +++ /dev/null @@ -1,17 +0,0 @@ -// TODO: remove this file, uneccessary - -// const useAddress = () => { -// const { service } = useServices(); - -// /** agent safe multisig address */ -// const multisigAddress = -// service?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data -// ?.multisig; - -// /** agent instance EOA address */ -// const instanceAddress = -// service?.chain_configs?.[CHAIN_CONFIG.OPTIMISM.chainId]?.chain_data -// ?.instances?.[0]; - -// return { instanceAddress, multisigAddress }; -// }; From 84b260ab13d6ed8c127ad9a0197318ecd50c9a12 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Thu, 21 Nov 2024 22:20:25 +0400 Subject: [PATCH 341/463] refactor: start refactoring useMigrate --- .../StakingContractSection/useMigrate.tsx | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index 7b859adf3..68c69f6c5 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -3,8 +3,14 @@ import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { TokenSymbol } from '@/enums/Token'; +import { + useBalanceContext, + useMasterBalances, + useServiceBalances, +} from '@/hooks/useBalanceContext'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; +import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { @@ -39,14 +45,17 @@ type MigrateValidation = }; export const useMigrate = (stakingProgramId: StakingProgramId) => { - const { serviceStatus } = useServices(); + const { selectedAgentConfig, selectedService } = useServices(); + const { homeChainId } = selectedAgentConfig; + const serviceConfigId = selectedService?.service_config_id; + const { deploymentStatus: serviceStatus } = useService({ + serviceConfigId, + }); const { serviceTemplate } = useServiceTemplates(); - const { - isBalanceLoaded, - masterSafeBalance: safeBalance, - totalOlasStakedBalance, - isLowBalance, - } = useBalanceContext(); + const { isLoaded: isBalanceLoaded } = useBalanceContext(); + const { serviceStakedBalances, isLowBalance } = + useServiceBalances(serviceConfigId); + const { masterSafeBalances } = useMasterBalances(); const { activeStakingProgramId, activeStakingProgramMeta } = useStakingProgram(); const { needsInitialFunding } = useNeedsFunds(); @@ -73,18 +82,34 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { const hasEnoughOlasToMigrate = useMemo(() => { if (!isBalanceLoaded) return false; - if (isNil(safeBalance?.OLAS)) return false; + // TODO: Josh please check if it's a correct replacement for safeBalance?.OLAS + const safeOlasBalance = masterSafeBalances?.find( + (item) => + item.chainId === homeChainId && item.symbol === TokenSymbol.OLAS, + )?.balance; + if (isNil(safeOlasBalance)) return false; + + const serviceStakedBalance = serviceStakedBalances?.find( + (item) => item.chainId === homeChainId, + ); + + // TODO: Josh please check if it's a correct replacement for totalOlasStakedBalance + // also it seems it makes sense to have it somewhere already calculated + const totalOlasStakedBalance = + (serviceStakedBalance?.olasBondBalance || 0) + + (serviceStakedBalance?.olasDepositBalance || 0); if (isNil(totalOlasStakedBalance)) return false; if (isNil(minimumOlasRequiredToMigrate)) return false; - const balanceForMigration = safeBalance.OLAS + totalOlasStakedBalance; + const balanceForMigration = safeOlasBalance + totalOlasStakedBalance; return balanceForMigration >= minimumOlasRequiredToMigrate; }, [ + homeChainId, isBalanceLoaded, + masterSafeBalances, minimumOlasRequiredToMigrate, - safeBalance, - totalOlasStakedBalance, + serviceStakedBalances, ]); const hasEnoughOlasForFirstRun = useMemo(() => { From e1432df63784db38310c5b1ee8c456efcb53c128 Mon Sep 17 00:00:00 2001 From: truemiller Date: Thu, 21 Nov 2024 18:36:13 +0000 Subject: [PATCH 342/463] refactor: fix useMigrate hook with agent type and balance calculations, add selectedAgentType to servicesContext --- .../StakingContractSection/useMigrate.tsx | 69 +++++++++++-------- frontend/context/ServicesProvider.tsx | 3 + 2 files changed, 42 insertions(+), 30 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index 68c69f6c5..67878d2a9 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -1,7 +1,8 @@ -import { isNil } from 'lodash'; +import { isEmpty, isNil } from 'lodash'; import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; +import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { StakingProgramId } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { @@ -12,7 +13,6 @@ import { import { useNeedsFunds } from '@/hooks/useNeedsFunds'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; -import { useServiceTemplates } from '@/hooks/useServiceTemplates'; import { useActiveStakingContractInfo, useStakingContractContext, @@ -45,19 +45,20 @@ type MigrateValidation = }; export const useMigrate = (stakingProgramId: StakingProgramId) => { - const { selectedAgentConfig, selectedService } = useServices(); + const { selectedAgentConfig, selectedService, selectedAgentType } = + useServices(); const { homeChainId } = selectedAgentConfig; const serviceConfigId = selectedService?.service_config_id; const { deploymentStatus: serviceStatus } = useService({ serviceConfigId, }); - const { serviceTemplate } = useServiceTemplates(); - const { isLoaded: isBalanceLoaded } = useBalanceContext(); - const { serviceStakedBalances, isLowBalance } = - useServiceBalances(serviceConfigId); + const { + isLoaded: isBalanceLoaded, + totalStakedOlasBalance: totalOlasStakedBalance, + } = useBalanceContext(); + const { isLowBalance } = useServiceBalances(serviceConfigId); const { masterSafeBalances } = useMasterBalances(); - const { activeStakingProgramId, activeStakingProgramMeta } = - useStakingProgram(); + const { activeStakingProgramId } = useStakingProgram(); const { needsInitialFunding } = useNeedsFunds(); const { @@ -76,28 +77,20 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { const { hasEnoughEthForInitialFunding } = useNeedsFunds(); const minimumOlasRequiredToMigrate = useMemo( - () => getMinimumStakedAmountRequired(serviceTemplate, stakingProgramId), // TODO: refactor, can no longer use service template, must use config for funding requirements - [serviceTemplate, stakingProgramId], + () => + STAKING_PROGRAMS[selectedAgentConfig.homeChainId][stakingProgramId] + .stakingRequirements[TokenSymbol.OLAS], + [selectedAgentConfig.homeChainId, stakingProgramId], ); const hasEnoughOlasToMigrate = useMemo(() => { if (!isBalanceLoaded) return false; - // TODO: Josh please check if it's a correct replacement for safeBalance?.OLAS const safeOlasBalance = masterSafeBalances?.find( (item) => item.chainId === homeChainId && item.symbol === TokenSymbol.OLAS, )?.balance; if (isNil(safeOlasBalance)) return false; - const serviceStakedBalance = serviceStakedBalances?.find( - (item) => item.chainId === homeChainId, - ); - - // TODO: Josh please check if it's a correct replacement for totalOlasStakedBalance - // also it seems it makes sense to have it somewhere already calculated - const totalOlasStakedBalance = - (serviceStakedBalance?.olasBondBalance || 0) + - (serviceStakedBalance?.olasDepositBalance || 0); if (isNil(totalOlasStakedBalance)) return false; if (isNil(minimumOlasRequiredToMigrate)) return false; @@ -109,16 +102,26 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { isBalanceLoaded, masterSafeBalances, minimumOlasRequiredToMigrate, - serviceStakedBalances, + totalOlasStakedBalance, ]); + const safeOlasBalance = useMemo(() => { + if (!isBalanceLoaded) return 0; + if (isNil(masterSafeBalances) || isEmpty(masterSafeBalances)) return 0; + masterSafeBalances.reduce((acc, { chainId, symbol, balance }) => { + if (chainId === homeChainId && symbol === TokenSymbol.OLAS) + return acc + balance; + return acc; + }, 0); + }, [homeChainId, isBalanceLoaded, masterSafeBalances]); + const hasEnoughOlasForFirstRun = useMemo(() => { if (!isBalanceLoaded) return false; - if (isNil(safeBalance?.OLAS)) return false; + if (isNil(safeOlasBalance)) return false; if (isNil(minimumOlasRequiredToMigrate)) return false; - return safeBalance.OLAS >= minimumOlasRequiredToMigrate; - }, [isBalanceLoaded, minimumOlasRequiredToMigrate, safeBalance]); + return safeOlasBalance >= minimumOlasRequiredToMigrate; + }, [isBalanceLoaded, minimumOlasRequiredToMigrate, safeOlasBalance]); const migrateValidation = useMemo(() => { if (!isServicesLoaded) { @@ -128,9 +131,9 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { // Services must be not be running or in a transitional state if ( [ - DeploymentStatus.DEPLOYED, - DeploymentStatus.DEPLOYING, - DeploymentStatus.STOPPING, + MiddlewareDeploymentStatus.DEPLOYED, + MiddlewareDeploymentStatus.DEPLOYING, + MiddlewareDeploymentStatus.STOPPING, ].some((status) => status === serviceStatus) ) { return { @@ -205,7 +208,12 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { // user must be staked from hereon - if (!activeStakingProgramMeta?.canMigrateTo.includes(stakingProgramId)) { + if ( + !STAKING_PROGRAMS[homeChainId][stakingProgramId].deprecated || + !STAKING_PROGRAMS[homeChainId][stakingProgramId].agentsSupported.includes( + selectedAgentType, + ) + ) { return { canMigrate: false, reason: CantMigrateReason.MigrationNotSupported, @@ -229,7 +237,8 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { stakingProgramId, hasEnoughOlasToMigrate, isServiceStaked, - activeStakingProgramMeta?.canMigrateTo, + homeChainId, + selectedAgentType, isServiceStakedForMinimumDuration, serviceStatus, ]); diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index ec3a673a1..dd4c8ee0b 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -38,6 +38,7 @@ type ServicesContextType = { selectService: (serviceUuid: string) => void; selectedService?: Service; selectedAgentConfig: AgentConfig; + selectedAgentType: AgentType; updateAgentType: (agentType: AgentType) => void; } & Partial> & UsePause; @@ -48,6 +49,7 @@ export const ServicesContext = createContext({ togglePaused: noop, selectService: noop, selectedAgentConfig: AGENT_CONFIG[AgentType.PredictTrader], + selectedAgentType: AgentType.PredictTrader, updateAgentType: noop, }); @@ -207,6 +209,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { selectService, selectedService, selectedAgentConfig, + selectedAgentType, updateAgentType, }} > From 6e02571cfd98e0256b18eef6910e9a58fc7980ca Mon Sep 17 00:00:00 2001 From: Atatakai Date: Fri, 22 Nov 2024 00:42:43 +0400 Subject: [PATCH 343/463] refactor: update useMigrate and related components --- .../CantMigrateAlert.tsx | 75 ++++++++++++++----- .../StakingContractSection/MigrateButton.tsx | 43 ++++++----- .../StakingContractSection/useMigrate.tsx | 59 +++++++-------- frontend/context/BalanceProvider.tsx | 5 ++ frontend/hooks/useBalanceContext.ts | 38 +--------- frontend/hooks/useStakingContractDetails.ts | 8 +- 6 files changed, 120 insertions(+), 108 deletions(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx index e0ded6024..8bfe0eef3 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx @@ -1,17 +1,24 @@ import { Flex, Typography } from 'antd'; -import { isNil } from 'lodash'; +import { isEmpty, isNil } from 'lodash'; +import { useMemo } from 'react'; import { CustomAlert } from '@/components/Alert'; +import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { LOW_MASTER_SAFE_BALANCE } from '@/constants/thresholds'; +import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { TokenSymbol } from '@/enums/Token'; +import { + useBalanceContext, + useMasterBalances, +} from '@/hooks/useBalanceContext'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; -import { useServiceTemplates } from '@/hooks/useServiceTemplates'; +import { useService } from '@/hooks/useService'; +import { useServices } from '@/hooks/useServices'; import { useActiveStakingContractInfo, useStakingContractContext, } from '@/hooks/useStakingContractDetails'; -import { getMinimumStakedAmountRequired } from '@/utils/service'; import { CantMigrateReason } from './useMigrate'; @@ -20,33 +27,65 @@ const { Text } = Typography; type CantMigrateAlertProps = { stakingProgramId: StakingProgramId }; const AlertInsufficientMigrationFunds = ({ - stakingProgramId, + stakingProgramId: stakingProgramIdToMigrateTo, }: CantMigrateAlertProps) => { - const { serviceTemplate } = useServiceTemplates(); + const { + isFetched: isServicesLoaded, + selectedService, + selectedAgentConfig, + } = useServices(); + const { homeChainId } = selectedAgentConfig; + const serviceConfigId = + isServicesLoaded && selectedService + ? selectedService.service_config_id + : ''; + const { service } = useService({ + serviceConfigId, + }); const { isAllStakingContractDetailsRecordLoaded } = useStakingContractContext(); const { isServiceStaked } = useActiveStakingContractInfo(); - const { masterSafeBalance: safeBalance, totalOlasStakedBalance } = + const { isLoaded: isBalanceLoaded, totalStakedOlasBalance } = useBalanceContext(); + const { masterSafeBalances } = useMasterBalances(); const { serviceFundRequirements, isInitialFunded } = useNeedsFunds(); - const totalOlasRequiredForStaking = getMinimumStakedAmountRequired( - serviceTemplate, - stakingProgramId, - ); + // should find in STAKING_PROGRAMS based on stakingProgramIdToMigrateTo? + const chainIdToMigrateTo = ChainId.Gnosis; + + const requiredStakedOlas = + service && + STAKING_PROGRAMS[chainIdToMigrateTo][stakingProgramIdToMigrateTo] + ?.stakingRequirements[TokenSymbol.OLAS]; + + const safeBalance = useMemo(() => { + if (!isBalanceLoaded) return; + if (isNil(masterSafeBalances) || isEmpty(masterSafeBalances)) return; + masterSafeBalances.reduce( + (acc, { chainId, symbol, balance }) => { + if (chainId === homeChainId) { + acc[symbol] = balance; + } + return acc; + }, + {} as Record, + ); + }, [homeChainId, isBalanceLoaded, masterSafeBalances]); if (!isAllStakingContractDetailsRecordLoaded) return null; - if (isNil(totalOlasRequiredForStaking)) return null; - if (isNil(safeBalance?.OLAS)) return null; - if (isNil(totalOlasStakedBalance)) return null; + if (isNil(requiredStakedOlas)) return null; + if (isNil(safeBalance?.[TokenSymbol.OLAS])) return null; + if (isNil(totalStakedOlasBalance)) return null; const requiredOlasDeposit = isServiceStaked - ? totalOlasRequiredForStaking - (totalOlasStakedBalance + safeBalance.OLAS) // when staked - : totalOlasRequiredForStaking - safeBalance.OLAS; // when not staked + ? requiredStakedOlas - + (totalStakedOlasBalance + safeBalance[TokenSymbol.OLAS]) // when staked + : requiredStakedOlas - safeBalance[TokenSymbol.OLAS]; // when not staked const requiredXdaiDeposit = isInitialFunded - ? LOW_MASTER_SAFE_BALANCE - safeBalance.ETH // is already funded allow minimal maintenance - : serviceFundRequirements.eth - safeBalance.ETH; // otherwise require full initial funding requirements + ? LOW_MASTER_SAFE_BALANCE - (safeBalance[TokenSymbol.ETH] || 0) // is already funded allow minimal maintenance + : (serviceFundRequirements[homeChainId]?.[TokenSymbol.ETH] || 0) - + (safeBalance[TokenSymbol.ETH] || 0); // otherwise require full initial funding requirements return ( { const { goto } = usePageState(); - const { serviceTemplate } = useServiceTemplates(); const { setPaused: setIsServicePollingPaused, isFetched: isServicesLoaded, selectedService, + selectedAgentConfig, } = useServices(); - - const { setDeploymentStatus } = useService({ - serviceConfigId: - isServicesLoaded && selectedService - ? selectedService.service_config_id - : '', + const { homeChainId } = selectedAgentConfig; + const serviceConfigId = + isServicesLoaded && selectedService + ? selectedService.service_config_id + : ''; + const { service, setDeploymentStatus } = useService({ + serviceConfigId, }); + const serviceTemplate = useMemo( + () => (service ? getServiceTemplate(service.hash) : undefined), + [service], + ); const { setIsPaused: setIsBalancePollingPaused } = useBalanceContext(); + const { initialDefaultStakingProgramId } = useStakingProgram(); const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded } = useActiveStakingContractInfo(); const { stakingContractInfo: defaultStakingContractInfo } = - useStakingContractDetails(defaultStakingProgramId); + useStakingContractDetails(initialDefaultStakingProgramId); const currentStakingContractInfo = useMemo(() => { if (!isActiveStakingContractDetailsLoaded) return; @@ -98,6 +105,8 @@ export const MigrateButton = ({ size="large" disabled={!validation.canMigrate} onClick={async () => { + if (!serviceTemplate) return; + setIsServicePollingPaused(true); setIsBalancePollingPaused(true); @@ -111,20 +120,20 @@ export const MigrateButton = ({ // update service await ServicesService.updateService({ - stakingProgramId, + stakingProgramId: stakingProgramIdToMigrateTo, serviceTemplate, - serviceUuid: serviceTemplate.service_config_id, + serviceUuid: serviceConfigId, deploy: true, useMechMarketplace: - stakingProgramId === StakingProgramId.BetaMechMarketplace, + stakingProgramIdToMigrateTo === + StakingProgramId.PearlBetaMechMarketplace, + chainId: homeChainId, }); // start service after updating - await ServicesService.startService( - serviceTemplate.service_config_id, - ); + await ServicesService.startService(serviceConfigId); - await updateStakingProgram(); // TODO: refactor to support single staking program & multi staking programs, this on longer works + // await updateStakingProgram(); // TODO: refactor to support single staking program & multi staking programs, this on longer works setMigrationModalOpen(true); } catch (error) { diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index 67878d2a9..64d16aef6 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -8,7 +8,6 @@ import { TokenSymbol } from '@/enums/Token'; import { useBalanceContext, useMasterBalances, - useServiceBalances, } from '@/hooks/useBalanceContext'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; import { useService } from '@/hooks/useService'; @@ -45,36 +44,46 @@ type MigrateValidation = }; export const useMigrate = (stakingProgramId: StakingProgramId) => { - const { selectedAgentConfig, selectedService, selectedAgentType } = - useServices(); + const { + isFetched: isServicesLoaded, + selectedAgentConfig, + selectedService, + selectedAgentType, + } = useServices(); const { homeChainId } = selectedAgentConfig; const serviceConfigId = selectedService?.service_config_id; const { deploymentStatus: serviceStatus } = useService({ serviceConfigId, }); + const { isLoaded: isBalanceLoaded, - totalStakedOlasBalance: totalOlasStakedBalance, + totalStakedOlasBalance, + isLowBalance, } = useBalanceContext(); - const { isLowBalance } = useServiceBalances(serviceConfigId); const { masterSafeBalances } = useMasterBalances(); - const { activeStakingProgramId } = useStakingProgram(); - const { needsInitialFunding } = useNeedsFunds(); + const { needsInitialFunding, hasEnoughEthForInitialFunding } = + useNeedsFunds(serviceConfigId); + const { activeStakingProgramId } = useStakingProgram(); const { allStakingContractDetailsRecord, isAllStakingContractDetailsRecordLoaded, } = useStakingContractContext(); - const { isServiceStaked, isServiceStakedForMinimumDuration } = useActiveStakingContractInfo(); - const { stakingContractInfo, hasEnoughServiceSlots } = useStakingContractDetails(stakingProgramId); - const { isFetched: isServicesLoaded } = useServices(); - - const { hasEnoughEthForInitialFunding } = useNeedsFunds(); + const safeOlasBalance = useMemo(() => { + if (!isBalanceLoaded) return 0; + if (isNil(masterSafeBalances) || isEmpty(masterSafeBalances)) return 0; + masterSafeBalances.reduce((acc, { chainId, symbol, balance }) => { + if (chainId === homeChainId && symbol === TokenSymbol.OLAS) + return acc + balance; + return acc; + }, 0); + }, [homeChainId, isBalanceLoaded, masterSafeBalances]); const minimumOlasRequiredToMigrate = useMemo( () => @@ -82,39 +91,21 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { .stakingRequirements[TokenSymbol.OLAS], [selectedAgentConfig.homeChainId, stakingProgramId], ); - const hasEnoughOlasToMigrate = useMemo(() => { if (!isBalanceLoaded) return false; - const safeOlasBalance = masterSafeBalances?.find( - (item) => - item.chainId === homeChainId && item.symbol === TokenSymbol.OLAS, - )?.balance; if (isNil(safeOlasBalance)) return false; - - if (isNil(totalOlasStakedBalance)) return false; + if (isNil(totalStakedOlasBalance)) return false; if (isNil(minimumOlasRequiredToMigrate)) return false; - const balanceForMigration = safeOlasBalance + totalOlasStakedBalance; - + const balanceForMigration = safeOlasBalance + totalStakedOlasBalance; return balanceForMigration >= minimumOlasRequiredToMigrate; }, [ - homeChainId, isBalanceLoaded, - masterSafeBalances, minimumOlasRequiredToMigrate, - totalOlasStakedBalance, + safeOlasBalance, + totalStakedOlasBalance, ]); - const safeOlasBalance = useMemo(() => { - if (!isBalanceLoaded) return 0; - if (isNil(masterSafeBalances) || isEmpty(masterSafeBalances)) return 0; - masterSafeBalances.reduce((acc, { chainId, symbol, balance }) => { - if (chainId === homeChainId && symbol === TokenSymbol.OLAS) - return acc + balance; - return acc; - }, 0); - }, [homeChainId, isBalanceLoaded, masterSafeBalances]); - const hasEnoughOlasForFirstRun = useMemo(() => { if (!isBalanceLoaded) return false; if (isNil(safeOlasBalance)) return false; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index a62682a9f..991ca8775 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -58,6 +58,7 @@ export const BalanceContext = createContext<{ balance: number; expectedBalance: number; }[]; + isLowBalance: boolean; isPaused: boolean; }>({ isLoaded: false, @@ -71,6 +72,7 @@ export const BalanceContext = createContext<{ totalEthBalance: 0, totalStakedOlasBalance: 0, lowBalances: [], + isLowBalance: false, }); export const BalanceProvider = ({ children }: PropsWithChildren) => { @@ -196,6 +198,8 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { return result; }, [services, stakedBalances, wallets, walletBalances]); + const isLowBalance = useMemo(() => lowBalances?.length > 0, [lowBalances]); + const updateBalances = useCallback(async () => { if (wallets && services) { setIsUpdatingBalances(true); @@ -244,6 +248,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { totalEthBalance, totalStakedOlasBalance, lowBalances, + isLowBalance, }} > {children} diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index 5a7f744f3..d0f62d54a 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -16,7 +16,7 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { const { flatAddresses, serviceSafes, serviceEoa } = useService({ serviceConfigId, }); - const { walletBalances, lowBalances, stakedBalances } = useBalanceContext(); + const { walletBalances, stakedBalances } = useBalanceContext(); /** * Staked balances, only relevant to safes @@ -29,20 +29,6 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { [flatAddresses, stakedBalances], ); - /** Array of cross-chain wallet balances relevant to the service with is considered low */ - const serviceLowBalances = useMemo( - () => lowBalances?.filter((balance) => balance.walletAddress), - [lowBalances], - ); - - /** - * Boolean indicating if the service has low balances - */ - const isLowBalance = useMemo( - () => serviceLowBalances?.length > 0, - [serviceLowBalances], - ); - /** * Cross-chain unstaked balances in service safes */ @@ -80,8 +66,6 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { serviceStakedBalances, serviceSafeBalances, serviceEoaBalances, - serviceLowBalances, - isLowBalance, }; }; @@ -92,7 +76,7 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { */ export const useMasterBalances = () => { const { masterSafes, masterEoa } = useMasterWalletContext(); - const { walletBalances, lowBalances } = useBalanceContext(); + const { walletBalances } = useBalanceContext(); // TODO: unused, check only services stake? // const masterStakedBalances = useMemo( @@ -128,27 +112,9 @@ export const useMasterBalances = () => { [masterEoaBalances, masterSafeBalances], ); - /** - * Array of low balances relevant to the master wallets (safes and eoa) - */ - const masterLowBalances = useMemo( - () => lowBalances?.filter((balance) => balance.walletAddress), - [lowBalances], - ); - - /** - * Boolean indicating if any master wallets have low balances - */ - const isLowBalance = useMemo( - () => masterLowBalances?.length > 0, - [masterLowBalances], - ); - return { masterWalletBalances, masterSafeBalances, masterEoaBalances, - masterLowBalances, - isLowBalance, }; }; diff --git a/frontend/hooks/useStakingContractDetails.ts b/frontend/hooks/useStakingContractDetails.ts index 76bff9bae..b0cd418f2 100644 --- a/frontend/hooks/useStakingContractDetails.ts +++ b/frontend/hooks/useStakingContractDetails.ts @@ -4,6 +4,7 @@ import { useContext } from 'react'; import { StakingContractDetailsContext } from '@/context/StakingContractDetailsProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; import { StakingState } from '@/types/Autonolas'; +import { Maybe } from '@/types/Util'; import { useServices } from './useServices'; @@ -120,11 +121,12 @@ export const useActiveStakingContractInfo = () => { }; export const useStakingContractDetails = ( - stakingProgramId: StakingProgramId, + stakingProgramId: Maybe, ) => { const { allStakingContractDetailsRecord } = useStakingContractContext(); - const stakingContractInfo = - allStakingContractDetailsRecord?.[stakingProgramId]; + const stakingContractInfo = stakingProgramId + ? allStakingContractDetailsRecord?.[stakingProgramId] + : null; const { serviceIds, maxNumServices, availableRewards } = stakingContractInfo ?? {}; From 84838a2f27224d8c8252859b0b237e808698a431 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Fri, 22 Nov 2024 12:29:01 +0400 Subject: [PATCH 344/463] refactor: main alerts and modals --- frontend/components/MainPage/header/index.tsx | 2 +- frontend/components/MainPage/index.tsx | 3 +- .../MainPage/modals/FirstRunModal.tsx | 19 ++++-- .../AlertSections/LowTradingBalanceAlert.tsx | 2 +- .../MainPage/sections/GasBalanceSection.tsx | 66 ++++++++++--------- .../sections/KeepAgentRunningSection.tsx | 7 +- 6 files changed, 59 insertions(+), 40 deletions(-) diff --git a/frontend/components/MainPage/header/index.tsx b/frontend/components/MainPage/header/index.tsx index 99afc59f0..036af9f57 100644 --- a/frontend/components/MainPage/header/index.tsx +++ b/frontend/components/MainPage/header/index.tsx @@ -13,7 +13,7 @@ import { AgentButton } from './AgentButton/AgentButton'; import { AgentHead } from './AgentHead'; const useSetupTrayIcon = () => { - const { lowBalances } = useBalanceContext(); + const { isLowBalance } = useBalanceContext(); const { selectedService } = useServices(); const { deploymentStatus } = useService({ serviceConfigId: selectedService?.service_config_id, diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index 240009ef1..7e444272d 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -9,6 +9,7 @@ import { usePageState } from '@/hooks/usePageState'; import { MainHeader } from './header'; import { AddFundsSection } from './sections/AddFundsSection'; import { AlertSections } from './sections/AlertSections'; +import { GasBalanceSection } from './sections/GasBalanceSection'; import { KeepAgentRunningSection } from './sections/KeepAgentRunningSection'; import { MainNeedsFunds } from './sections/NeedsFundsSection'; import { MainOlasBalance } from './sections/OlasBalanceSection'; @@ -90,7 +91,7 @@ export const Main = () => { - {/* */} + diff --git a/frontend/components/MainPage/modals/FirstRunModal.tsx b/frontend/components/MainPage/modals/FirstRunModal.tsx index 803cc8c3f..95e3d57f5 100644 --- a/frontend/components/MainPage/modals/FirstRunModal.tsx +++ b/frontend/components/MainPage/modals/FirstRunModal.tsx @@ -2,21 +2,28 @@ import { Button, Flex, Modal, Typography } from 'antd'; import Image from 'next/image'; import { FC } from 'react'; +import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { MODAL_WIDTH } from '@/constants/width'; -import { useServiceTemplates } from '@/hooks/useServiceTemplates'; +import { TokenSymbol } from '@/enums/Token'; +import { useServices } from '@/hooks/useServices'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; const { Title, Paragraph } = Typography; type FirstRunModalProps = { open: boolean; onClose: () => void }; export const FirstRunModal: FC = ({ open, onClose }) => { - const { getServiceTemplates } = useServiceTemplates(); + const { selectedAgentConfig } = useServices(); + const { homeChainId } = selectedAgentConfig; + const { activeStakingProgramId } = useStakingProgram(); if (!open) return null; + if (!activeStakingProgramId) return null; - const minimumStakedAmountRequired = getMinimumStakedAmountRequired( - getServiceTemplates()[0], - ); + const requiredStakedOlas = + STAKING_PROGRAMS[homeChainId][activeStakingProgramId]?.stakingRequirements[ + TokenSymbol.OLAS + ]; return ( = ({ open, onClose }) => { /> - {`Your agent is running and you've staked ${minimumStakedAmountRequired} OLAS!`} + {`Your agent is running and you've staked ${requiredStakedOlas} OLAS!`} Your agent is working towards earning rewards. diff --git a/frontend/components/MainPage/sections/AlertSections/LowTradingBalanceAlert.tsx b/frontend/components/MainPage/sections/AlertSections/LowTradingBalanceAlert.tsx index 43a13322e..1993859ac 100644 --- a/frontend/components/MainPage/sections/AlertSections/LowTradingBalanceAlert.tsx +++ b/frontend/components/MainPage/sections/AlertSections/LowTradingBalanceAlert.tsx @@ -8,7 +8,7 @@ import { useStore } from '@/hooks/useStore'; const { Text, Title } = Typography; export const LowTradingBalanceAlert = () => { - const { isBalanceLoaded, isLowBalance } = useBalanceContext(); + const { isLoaded: isBalanceLoaded, isLowBalance } = useBalanceContext(); const { storeState } = useStore(); if (!isBalanceLoaded) return null; diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index f41c083ce..aef1675b6 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -1,13 +1,15 @@ -import { InfoCircleOutlined } from '@ant-design/icons'; +import { ArrowUpOutlined, InfoCircleOutlined } from '@ant-design/icons'; import { Skeleton, Tooltip, Typography } from 'antd'; import { isNil } from 'lodash'; import { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; +import { EXPLORER_URL } from '@/constants/urls'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useService } from '@/hooks/useService'; +import { useServices } from '@/hooks/useServices'; import { useStore } from '@/hooks/useStore'; import { CardSection } from '../../styled/CardSection'; @@ -33,20 +35,14 @@ const FineDot = styled(Dot)` background-color: ${COLOR.GREEN_2}; `; -const BalanceStatus = ({ serviceConfigId }: { serviceConfigId: string }) => { - const { isLoaded, lowBalances } = useBalanceContext(); +const BalanceStatus = () => { + const { isLoaded, isLowBalance } = useBalanceContext(); const { storeState } = useStore(); const { showNotification } = useElectronApi(); const [isLowBalanceNotificationShown, setIsLowBalanceNotificationShown] = useState(false); - const isLowBalance = - lowBalances.filter( - (lowBalanceResult) => - lowBalanceResult.serviceConfigId === serviceConfigId, - ).length > 0; - // show notification if balance is too low useEffect(() => { if (!isLoaded) return; @@ -100,12 +96,21 @@ const TooltipContent = styled.div` } `; -type GasBalanceSectionProps = { serviceConfigId: string }; -export const GasBalanceSection = ({ - serviceConfigId, -}: GasBalanceSectionProps) => { - const { isLoaded } = useBalanceContext(); - const { serviceSafes } = useService({ serviceConfigId }); +export const GasBalanceSection = () => { + const { selectedService, isFetched: isLoaded } = useServices(); + const serviceConfigId = + isLoaded && selectedService ? selectedService?.service_config_id : ''; + const { serviceSafes } = useService({ + serviceConfigId, + }); + const { isLoaded: isBalancesLoaded } = useBalanceContext(); + + const chainId = selectedService?.home_chain_id; + const serviceSafe = useMemo(() => { + if (!chainId) return; + + return serviceSafes.find((wallet) => wallet.chainId === chainId); + }, [chainId, serviceSafes]); return ( Trading balance  - {serviceSafes.length > 0 && ( + {serviceSafe && ( Your agent uses this balance to fund trading activity on-chain. - {/* TODO: reintroduce, low priority */} - {/*
- - Track activity on blockchain explorer{' '} - - */} +
+ {chainId && ( + + Track activity on blockchain explorer{' '} + + + )} } > @@ -141,9 +147,9 @@ export const GasBalanceSection = ({ )}
- {isLoaded ? ( + {isBalancesLoaded ? ( - + ) : ( diff --git a/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx b/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx index 3de7bb8b4..fdd8e8a0a 100644 --- a/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx +++ b/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx @@ -1,6 +1,7 @@ import { Flex, Typography } from 'antd'; import { MiddlewareDeploymentStatus } from '@/client'; +import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useStore } from '@/hooks/useStore'; @@ -13,7 +14,11 @@ const cardSectionStyle = { marginBottom: '-1px', marginTop: '24px' }; export const KeepAgentRunningSection = () => { const { storeState } = useStore(); - const { serviceStatus } = useServices(); + + const { selectedService } = useServices(); + const { deploymentStatus: serviceStatus } = useService({ + serviceConfigId: selectedService?.service_config_id, + }); if (storeState?.firstStakingRewardAchieved) return null; if (serviceStatus !== MiddlewareDeploymentStatus.DEPLOYED) return null; From ff8d3113a831fe917179df58e7087bfce3b73141 Mon Sep 17 00:00:00 2001 From: Atatakai Date: Fri, 22 Nov 2024 13:08:26 +0400 Subject: [PATCH 345/463] refactor: change agentSafe to masterSafe --- .../MainPage/sections/GasBalanceSection.tsx | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index aef1675b6..435945fcb 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -8,9 +8,9 @@ import { COLOR } from '@/constants/colors'; import { EXPLORER_URL } from '@/constants/urls'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; -import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useStore } from '@/hooks/useStore'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { CardSection } from '../../styled/CardSection'; @@ -97,20 +97,16 @@ const TooltipContent = styled.div` `; export const GasBalanceSection = () => { - const { selectedService, isFetched: isLoaded } = useServices(); - const serviceConfigId = - isLoaded && selectedService ? selectedService?.service_config_id : ''; - const { serviceSafes } = useService({ - serviceConfigId, - }); + const { selectedAgentConfig } = useServices(); + const { homeChainId } = selectedAgentConfig; + const { masterSafes } = useMasterWalletContext(); const { isLoaded: isBalancesLoaded } = useBalanceContext(); - const chainId = selectedService?.home_chain_id; - const serviceSafe = useMemo(() => { - if (!chainId) return; + const masterSafe = useMemo(() => { + if (isNil(masterSafes)) return; - return serviceSafes.find((wallet) => wallet.chainId === chainId); - }, [chainId, serviceSafes]); + return masterSafes.find((wallet) => wallet.chainId === homeChainId); + }, [homeChainId, masterSafes]); return ( { > Trading balance  - {serviceSafe && ( + {masterSafe && ( Your agent uses this balance to fund trading activity on-chain.
- {chainId && ( - - Track activity on blockchain explorer{' '} - - - )} + + Track activity on blockchain explorer{' '} + + } > From 673458d34b2a8fa99da7a8916d0bef7dfdb4975b Mon Sep 17 00:00:00 2001 From: Atatakai Date: Fri, 22 Nov 2024 13:18:13 +0400 Subject: [PATCH 346/463] refactor: remove service check --- .../StakingContractSection/CantMigrateAlert.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx index 8bfe0eef3..e069dd485 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx @@ -54,7 +54,6 @@ const AlertInsufficientMigrationFunds = ({ const chainIdToMigrateTo = ChainId.Gnosis; const requiredStakedOlas = - service && STAKING_PROGRAMS[chainIdToMigrateTo][stakingProgramIdToMigrateTo] ?.stakingRequirements[TokenSymbol.OLAS]; From 7cf3170dec5496c0cc49dd38c35cefe341cc2f83 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 10:43:07 +0000 Subject: [PATCH 347/463] refactor: enhance query enabling conditions in useMultisig hook --- frontend/hooks/useMultisig.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/hooks/useMultisig.ts b/frontend/hooks/useMultisig.ts index 9cd930bf1..c3cf6326b 100644 --- a/frontend/hooks/useMultisig.ts +++ b/frontend/hooks/useMultisig.ts @@ -1,7 +1,7 @@ import { useQuery } from '@tanstack/react-query'; import { Contract } from 'ethers'; import { Contract as MulticallContract, ContractCall } from 'ethers-multicall'; -import { isEmpty } from 'lodash'; +import { isEmpty, isNil } from 'lodash'; import { GNOSIS_SAFE_ABI } from '@/abis/gnosisSafe'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; @@ -22,6 +22,7 @@ export const useMultisig = (safe?: Safe) => { isFetched: ownersIsFetched, isPending: ownersIsPending, } = useQuery({ + enabled: !isNil(safe), queryKey: safe ? REACT_QUERY_KEYS.MULTISIG_GET_OWNERS_KEY(safe) : [], queryFn: async () => { if (!safe) { @@ -49,6 +50,7 @@ export const useMultisigs = (safes?: Safe[]) => { isFetched: ownersIsFetched, isPending: ownersIsPending, } = useQuery<{ safeAddress: string; chainId: number; owners: string[] }[]>({ + enabled: !isNil(safes) && !isEmpty(safes), queryKey: safes ? REACT_QUERY_KEYS.MULTISIGS_GET_OWNERS_KEY(safes) : [], queryFn: async (): Promise< { From 333d4d155875d8ad47ef51e7876780f9d0502699 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:56:39 +0000 Subject: [PATCH 348/463] Update frontend/hooks/useLogs.ts Co-authored-by: Mohan --- frontend/hooks/useLogs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index 20311d6fc..df027896b 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -59,7 +59,6 @@ const useAddressesLogs = () => { const useBalancesLogs = () => { const { masterWallets } = useMasterWalletContext(); - const { isLoaded: isBalanceLoaded, totalEthBalance, From 4360dd2193152ef8caae8ae1d564c052b59f522d Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:57:03 +0000 Subject: [PATCH 349/463] Update frontend/hooks/useLogs.ts Co-authored-by: Mohan --- frontend/hooks/useLogs.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index df027896b..297247a80 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -28,8 +28,7 @@ const useAddressesLogs = () => { if (!allMasterSafeOwners) return; const result = allMasterSafeOwners - .map((owners) => - owners.owners + .map(({ owners }) => .filter((owner): owner is Address => owner !== masterEoa.address) .map((owner) => ({ address: owner, From 9d194c4d1d15b112c9c94bbf5a310f63e1dd3d2f Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 11:06:30 +0000 Subject: [PATCH 350/463] feat: add middleware deployment status enums and refactor service hook logic --- frontend/client/enums.ts | 18 ++++++++++++++++++ frontend/hooks/useNotifyOnNewEpoch.ts | 10 +++++++--- frontend/hooks/useService.ts | 24 +++++++++++++++++++++++- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index 73f05d2c0..ea558cc6d 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -30,6 +30,24 @@ export enum MiddlewareDeploymentStatus { DELETED = 6, } +/** @note statuses where middleware deployment is moving from stopped to deployed, or vice versa, used for loading fallbacks */ +export const MiddlewareTransitioningStatuses = [ + MiddlewareDeploymentStatus.DEPLOYING, + MiddlewareDeploymentStatus.STOPPING, +]; + +/** @node statuses where middleware deployment is running */ +export const MiddlewareRunningStatuses = [ + MiddlewareDeploymentStatus.DEPLOYED, + ...MiddlewareTransitioningStatuses, +]; + +/** @note statuses where middleware is in the process of building/creating a new deployment */ +export const MiddlewareBuildingStatuses = [ + MiddlewareDeploymentStatus.BUILT, + MiddlewareDeploymentStatus.CREATED, +]; + export enum MiddlewareAccountIsSetup { True, False, diff --git a/frontend/hooks/useNotifyOnNewEpoch.ts b/frontend/hooks/useNotifyOnNewEpoch.ts index d3ce826c7..8827806bb 100644 --- a/frontend/hooks/useNotifyOnNewEpoch.ts +++ b/frontend/hooks/useNotifyOnNewEpoch.ts @@ -3,6 +3,7 @@ import { useEffect, useState } from 'react'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; +import { useService } from './useService'; import { useActiveStakingContractInfo } from './useStakingContractDetails'; type EpochStatusNotification = { @@ -16,7 +17,10 @@ type EpochStatusNotification = { */ export const useNotifyOnNewEpoch = () => { const { showNotification } = useElectronApi(); - const { isServiceNotRunning } = useServices(); //TODO: refactor to use single service hook + const { selectedService } = useServices(); //TODO: refactor to use single service hook + const { isServiceRunning } = useService({ + serviceConfigId: selectedService?.service_config_id, + }); const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded } = useActiveStakingContractInfo(); @@ -30,7 +34,7 @@ export const useNotifyOnNewEpoch = () => { if (!isActiveStakingContractDetailsLoaded) return; // if agent is running, no need to show notification - if (!isServiceNotRunning) return; + if (isServiceRunning) return; // latest epoch is not loaded yet if (!epoch) return; @@ -53,10 +57,10 @@ export const useNotifyOnNewEpoch = () => { setEpochStatusNotification({ lastEpoch: epoch, isNotified: true }); } }, [ - isServiceNotRunning, epochStatusNotification, epoch, isActiveStakingContractDetailsLoaded, showNotification, + isServiceRunning, ]); }; diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index a8fa5d717..6b97018c8 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -1,7 +1,11 @@ import { useQueryClient } from '@tanstack/react-query'; import { useMemo } from 'react'; -import { MiddlewareDeploymentStatus } from '@/client'; +import { + MiddlewareDeploymentStatus, + MiddlewareRunningStatuses, + MiddlewareTransitioningStatuses, +} from '@/client'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { ChainId } from '@/enums/Chain'; import { @@ -139,6 +143,21 @@ export const useService = ({ MiddlewareDeploymentStatus | undefined >(REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY(serviceConfigId)); + /** @note deployment is transitioning from stopped to deployed (and vice versa) */ + const isServiceTransitioning = deploymentStatus + ? MiddlewareTransitioningStatuses.includes(deploymentStatus) + : false; + + /** @note deployment is running, or transitioning, both assume the deployment is active */ + const isServiceRunning = deploymentStatus + ? MiddlewareRunningStatuses.includes(deploymentStatus) + : false; + + /** @note new deployment being created/built */ + const isServiceBuilding = deploymentStatus + ? MiddlewareTransitioningStatuses.includes(deploymentStatus) + : false; + return { service, addresses, @@ -148,6 +167,9 @@ export const useService = ({ setDeploymentStatus, serviceSafes, serviceEoa, + isServiceTransitioning, + isServiceRunning, + isServiceBuilding, }; }; From f7293466839906d29f9c0394fd916bf01695137a Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 11:08:51 +0000 Subject: [PATCH 351/463] chore: remove TODO comment --- frontend/hooks/useNotifyOnNewEpoch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/useNotifyOnNewEpoch.ts b/frontend/hooks/useNotifyOnNewEpoch.ts index 8827806bb..44eb64d4e 100644 --- a/frontend/hooks/useNotifyOnNewEpoch.ts +++ b/frontend/hooks/useNotifyOnNewEpoch.ts @@ -17,7 +17,7 @@ type EpochStatusNotification = { */ export const useNotifyOnNewEpoch = () => { const { showNotification } = useElectronApi(); - const { selectedService } = useServices(); //TODO: refactor to use single service hook + const { selectedService } = useServices(); const { isServiceRunning } = useService({ serviceConfigId: selectedService?.service_config_id, }); From 7931a36459f813350d6e46e546bd227c0e026df9 Mon Sep 17 00:00:00 2001 From: Mohan Date: Fri, 22 Nov 2024 16:58:18 +0530 Subject: [PATCH 352/463] refactor: Staking rewards (main page) (#485) * refactor: rename isBalanceLoaded to isLoaded in RewardsSection * feat: update reward display to use NA constant and refactor balance loading state --- .../RewardsSection/NotifyRewardsModal.tsx | 3 ++- .../sections/RewardsSection/RewardsStreak.tsx | 4 ++-- .../StakingRewardsThisEpoch.tsx | 5 +++-- .../sections/RewardsSection/index.tsx | 4 ++-- frontend/hooks/useStakingProgram.ts | 20 +++++-------------- 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx b/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx index d0662478e..7d5cf8bd2 100644 --- a/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/NotifyRewardsModal.tsx @@ -2,6 +2,7 @@ import { Button, Flex, Modal, Typography } from 'antd'; import Image from 'next/image'; import { useCallback, useEffect, useRef, useState } from 'react'; +import { NA } from '@/constants/symbols'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useReward } from '@/hooks/useReward'; @@ -13,7 +14,7 @@ import { ConfettiAnimation } from '../../../Confetti/ConfettiAnimation'; const { Text, Title } = Typography; const getFormattedReward = (reward: number | undefined) => - reward === undefined ? '--' : `~${balanceFormat(reward, 2)}`; + reward === undefined ? NA : `~${balanceFormat(reward, 2)}`; const SHARE_TEXT = `I just earned my first reward through the Operate app powered by #olas!\n\nDownload the Pearl app:`; const OPERATE_URL = 'https://olas.network/operate?pearl=first-reward'; diff --git a/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx b/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx index 7e915eddb..c1ec9dc07 100644 --- a/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/RewardsStreak.tsx @@ -6,7 +6,7 @@ import { FireNoStreak } from '@/components/custom-icons/FireNoStreak'; import { FireStreak } from '@/components/custom-icons/FireStreak'; import { COLOR } from '@/constants/colors'; import { NA } from '@/constants/symbols'; -import { Pages } from '@/enums/PageState'; +import { Pages } from '@/enums/Pages'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { usePageState } from '@/hooks/usePageState'; import { useReward } from '@/hooks/useReward'; @@ -22,7 +22,7 @@ const RewardsStreakFlex = styled(Flex)` `; const Streak = () => { - const { isBalanceLoaded } = useBalanceContext(); + const { isLoaded: isBalanceLoaded } = useBalanceContext(); const { isEligibleForRewards } = useReward(); const { latestRewardStreak: streak, diff --git a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx index 17540829c..0f25e36b1 100644 --- a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx @@ -3,6 +3,7 @@ import { useQuery } from '@tanstack/react-query'; import { Popover, Typography } from 'antd'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { NA } from '@/constants/symbols'; import { POPOVER_WIDTH_MEDIUM } from '@/constants/width'; import { getLatestEpochDetails } from '@/graphql/queries'; import { useServices } from '@/hooks/useServices'; @@ -29,7 +30,7 @@ const useEpochEndTime = () => { // last epoch end time + epoch length return Number(data.blockTimestamp) + Number(data.epochLength); }, - enabled: !!activeStakingProgramAddress, + enabled: !!activeStakingProgramAddress && !!chainId, refetchOnWindowFocus: false, }); @@ -58,7 +59,7 @@ export const StakingRewardsThisEpoch = () => { {epochEndTimeInMs ? `${formatToTime(epochEndTimeInMs * 1000)} (UTC)` - : '--'} + : NA} ) : ( diff --git a/frontend/components/MainPage/sections/RewardsSection/index.tsx b/frontend/components/MainPage/sections/RewardsSection/index.tsx index 2ec1ee1bf..aaee56c48 100644 --- a/frontend/components/MainPage/sections/RewardsSection/index.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/index.tsx @@ -23,7 +23,7 @@ const getFormattedReward = (reward: number | undefined) => const DisplayRewards = () => { const { availableRewardsForEpochEth, isEligibleForRewards } = useReward(); - const { isBalanceLoaded } = useBalanceContext(); + const { isLoaded } = useBalanceContext(); const reward = getFormattedReward(availableRewardsForEpochEth); @@ -36,7 +36,7 @@ const DisplayRewards = () => { borderbottom="true" > - {isBalanceLoaded ? ( + {isLoaded ? ( {reward} OLAS  {isEligibleForRewards ? ( diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index 5da704d74..980edf63a 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -7,6 +7,8 @@ import { } from '@/config/stakingPrograms'; import { StakingProgramContext } from '@/context/StakingProgramProvider'; import { StakingProgramId } from '@/enums/StakingProgram'; +import { Address } from '@/types/Address'; +import { Nullable } from '@/types/Util'; import { useServices } from './useServices'; @@ -25,7 +27,7 @@ export const useStakingProgram = () => { const allStakingProgramsKeys = Object.keys(STAKING_PROGRAMS[homeChainId]); const allStakingProgramNameAddressPair = STAKING_PROGRAM_ADDRESS[homeChainId]; - // TODO: refactor to support allStakingPrograms, previously this was intented solely for the active staking program + // TODO: refactor to support allStakingPrograms, previously this was intended solely for the active staking program const allStakingProgramsMeta = useMemo(() => { if (!isActiveStakingProgramLoaded) return null; if (!activeStakingProgramId) return null; @@ -59,21 +61,9 @@ export const useStakingProgram = () => { activeStakingProgramId, ]); - const activeStakingProgramAddress = useMemo(() => { + const activeStakingProgramAddress: Nullable
= useMemo(() => { if (!activeStakingProgramId) return null; - if (activeStakingProgramId.length === 0) return null; - - return ( - Object.keys(allStakingProgramNameAddressPair) as StakingProgramId[] - ).reduce( - (acc, programId) => { - if (activeStakingProgramId.includes(programId)) { - acc[programId] = allStakingProgramNameAddressPair[programId]; - } - return acc; - }, - {} as Record, - ); + return allStakingProgramNameAddressPair[activeStakingProgramId]; }, [allStakingProgramNameAddressPair, activeStakingProgramId]); return { From 7fa15f72fceefdece656f7ba730c46e759796774 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 12:08:39 +0000 Subject: [PATCH 353/463] refactor: update AddBackupWalletViaSafePage to use context and handle masterSafe --- .../Pages/AddBackupWalletViaSafePage/index.tsx | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx index bc26862f6..3053ceb39 100644 --- a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx +++ b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx @@ -1,10 +1,11 @@ import { Card, Flex, Typography } from 'antd'; +import { isNil } from 'lodash'; import { CardTitle } from '@/components/Card/CardTitle'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { DISCORD_TICKET_URL } from '@/constants/urls'; import { ChainId } from '@/enums/Chain'; -import { MasterSafe } from '@/enums/Wallet'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { GoToMainPageButton } from '../GoToMainPageButton'; @@ -20,10 +21,17 @@ const safeChainPrefix = { [ChainId.Gnosis]: 'gno', }; -export const AddBackupWalletViaSafePage = (masterSafe: MasterSafe) => { - const { chainId, address } = masterSafe; +export const AddBackupWalletViaSafePage = () => { + const { masterSafes } = useMasterWalletContext(); - const safePrefix = safeChainPrefix[chainId]; + const masterSafe = masterSafes?.[0]; // TODO: handle multiple safes better, currently only supporting a single safe for now + + const safePrefix = + masterSafe?.chainId && safeChainPrefix[masterSafe?.chainId]; + + if (isNil(masterSafe)) { + return null; + } return ( { Manually add backup wallet via Safe interface: Add backup wallet {UNICODE_SYMBOLS.EXTERNAL_LINK} From 2486f9d1e901fb411ed74d449872392ab4d95119 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:08:59 +0000 Subject: [PATCH 354/463] Update frontend/client/enums.ts Co-authored-by: Atatakai --- frontend/client/enums.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index ea558cc6d..96eafed0d 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -36,7 +36,7 @@ export const MiddlewareTransitioningStatuses = [ MiddlewareDeploymentStatus.STOPPING, ]; -/** @node statuses where middleware deployment is running */ +/** @note statuses where middleware deployment is running */ export const MiddlewareRunningStatuses = [ MiddlewareDeploymentStatus.DEPLOYED, ...MiddlewareTransitioningStatuses, From a6b3c4cd547402295b8b71ca3330e11097e30280 Mon Sep 17 00:00:00 2001 From: Josh Miller <31908788+truemiller@users.noreply.github.com> Date: Fri, 22 Nov 2024 12:09:34 +0000 Subject: [PATCH 355/463] Update frontend/hooks/useService.ts Co-authored-by: Atatakai --- frontend/hooks/useService.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index 6b97018c8..b0d2ec685 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -155,7 +155,7 @@ export const useService = ({ /** @note new deployment being created/built */ const isServiceBuilding = deploymentStatus - ? MiddlewareTransitioningStatuses.includes(deploymentStatus) + ? MiddlewareBuildingStatuses.includes(deploymentStatus) : false; return { From eb7d8ceabf9e077728fe4d8e68ecefb9d31346e2 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 12:16:05 +0000 Subject: [PATCH 356/463] refactor: enhance AddBackupWalletViaSafePage to utilize services and improve masterSafe handling --- .../components/Pages/AddBackupWalletViaSafePage/index.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx index 3053ceb39..a06d5b62c 100644 --- a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx +++ b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx @@ -5,6 +5,7 @@ import { CardTitle } from '@/components/Card/CardTitle'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { DISCORD_TICKET_URL } from '@/constants/urls'; import { ChainId } from '@/enums/Chain'; +import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { GoToMainPageButton } from '../GoToMainPageButton'; @@ -22,9 +23,14 @@ const safeChainPrefix = { }; export const AddBackupWalletViaSafePage = () => { + const { + selectedAgentConfig: { homeChainId }, + } = useServices(); const { masterSafes } = useMasterWalletContext(); - const masterSafe = masterSafes?.[0]; // TODO: handle multiple safes better, currently only supporting a single safe for now + const masterSafe = masterSafes?.find( + ({ chainId }) => homeChainId === chainId, + ); const safePrefix = masterSafe?.chainId && safeChainPrefix[masterSafe?.chainId]; From ca5b52434c5880d888862f25594e29620e6792a2 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 22 Nov 2024 13:55:29 +0100 Subject: [PATCH 357/463] chore: update cli --- api.md | 70 +++++++++++++++++++++++++++++++------------------- operate/cli.py | 64 +++++++++++++++++++-------------------------- 2 files changed, 70 insertions(+), 64 deletions(-) diff --git a/api.md b/api.md index baead9f81..3f7763b09 100644 --- a/api.md +++ b/api.md @@ -183,10 +183,12 @@ Returns a list of available wallets { "address": "0xFafd5cb31a611C5e5aa65ea8c6226EB4328175E7", "safe_chains": [ - 2 + "gnosis" ], "ledger_type": 0, - "safe": "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23", + "safes": { + "gnosis": "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23" + }, "safe_nonce": 110558881674480320952254000342160989674913430251257716940579305238321962891821 } ] @@ -253,15 +255,15 @@ Creates a Gnosis safe for given chain type. ```json { - "address": "0xaaFd5cb31A611C5e5aa65ea8c6226EB4328175E3", + "address": "0xFafd5cb31a611C5e5aa65ea8c6226EB4328175E7", "safe_chains": [ - 2 + "gnosis" ], "ledger_type": 0, "safes": { - "2": "0xe56fb574ce2C66008d5c4C09980c4f36Ab81ff22" + "gnosis": "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23" }, - "safe_nonce": 110558881674480320952254000342160989674913430251157716140571305138121962898821 + "safe_nonce": 110558881674480320952254000342160989674913430251257716940579305238321962891821 } ``` @@ -292,34 +294,50 @@ Updtes a Gnosis safe for given chain type. } ``` -or - -```js -{ - "chains": ["chain1", "chain2", ...], - "backup_owner": "0x650e83Bc808B8f405A9aF7CF68644cc817e084A6" -} -``` - -
Response -- If Gnosis safe creation is successful: +- If Gnosis safe update is successful: ```json { - "address": "0xaaFd5cb31A611C5e5aa65ea8c6226EB4328175E3", - "safe_chains": [ - 2 - ], - "ledger_type": 0, - "safes": { - "2": "0xe56fb574ce2C66008d5c4C09980c4f36Ab81ff22" - }, - "safe_nonce": 110558881674480320952254000342160989674913430251157716140571305138121962898821 + "backup_owner_updated": true, + "chain": "gnosis", + "message": "Backup owner updated.", + "wallet": { + "address": "0xFafd5cb31a611C5e5aa65ea8c6226EB4328175E7", + "safe_chains": [ + "gnosis" + ], + "ledger_type": 0, + "safes": { + "gnosis": "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23" + }, + "safe_nonce": 110558881674480320952254000342160989674913430251257716940579305238321962891821 + } + } + ``` + +- If Gnosis safe update is successful, but no changes required in the safe: + + ```json + { + "backup_owner_updated": false, + "chain": "gnosis", + "message": "No changes on backup owner. The backup owner provided matches the current one.", + "wallet": { + "address": "0xFafd5cb31a611C5e5aa65ea8c6226EB4328175E7", + "safe_chains": [ + "gnosis" + ], + "ledger_type": 0, + "safes": { + "gnosis": "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23" + }, + "safe_nonce": 110558881674480320952254000342160989674913430251257716940579305238321962891821 + } } ``` diff --git a/operate/cli.py b/operate/cli.py index 4b8be1604..446363591 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -598,51 +598,39 @@ async def _update_safe(request: Request) -> t.List[t.Dict]: status_code=401, ) - manager = operate.wallet_manager data = await request.json() - chains = [] - if "chain" in data: - if "chains" in data: - return JSONResponse( - content={ - "error": "You cannot specify 'chain' and 'chains' in the same request." - }, - status_code=401, - ) - chains = [Chain[data["chain"]]] - elif "chains" in data: - chains = [Chain(chain_str) for chain_str in data["chains"]] - - # check that all chains are supported - for chain in chains: - ledger_type = chain.ledger_type - if not manager.exists(ledger_type=ledger_type): - return JSONResponse( - content={ - "error": f"A wallet of type {ledger_type} does not exist for chain {chain}." - } - ) - - # update backup owners - updated_safes = {} - for chain in chains: - ledger_type = chain.ledger_type - wallet = manager.load(ledger_type=ledger_type) - updated = wallet.update_backup_owner( - chain=chain, - backup_owner=data.get("backup_owner"), + if "chain" not in data: + return JSONResponse( + content={"error": "You need to specify a chain to updae a safe."}, + status_code=401, ) - if updated: - updated_safes[chain.value] = wallet.safes[chain] - if not updated_safes: - return JSONResponse(content={"message": "No safes were updated."}) + chain = Chain(data["chain"]) + ledger_type = chain.ledger_type + manager = operate.wallet_manager + if not manager.exists(ledger_type=ledger_type): + return JSONResponse( + content={"error": "Wallet does not exist"}, + status_code=401, + ) + wallet = manager.load(ledger_type=ledger_type) + backup_owner_updated = wallet.update_backup_owner( + chain=chain, + backup_owner=data.get("backup_owner"), + ) + message = ( + "Backup owner updated." + if backup_owner_updated + else "No changes on backup owner. The backup owner provided matches the current one." + ) return JSONResponse( content={ - "updated_safes": updated_safes, - "message": "Safe backup owners updated.", + "wallet": wallet.json, + "chain": chain.value, + "backup_owner_updated": backup_owner_updated, + "message": message, } ) From d0c30580708a63abdf49b687556f7205efcf5c4b Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 22 Nov 2024 13:56:42 +0100 Subject: [PATCH 358/463] doc: typo --- api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.md b/api.md index 3f7763b09..6348a57b4 100644 --- a/api.md +++ b/api.md @@ -282,7 +282,7 @@ Creates a Gnosis safe for given chain type. ### `PUT /api/wallet/safe` -Updtes a Gnosis safe for given chain type. +Upadtes a Gnosis safe for given chain type.
Request From 228bfcdf816a8421aeba98f4a19145de50d65b98 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 22 Nov 2024 14:06:09 +0100 Subject: [PATCH 359/463] chore: updates --- api.md | 4 ++-- operate/cli.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api.md b/api.md index 6348a57b4..ab77b977f 100644 --- a/api.md +++ b/api.md @@ -282,7 +282,7 @@ Creates a Gnosis safe for given chain type. ### `PUT /api/wallet/safe` -Upadtes a Gnosis safe for given chain type. +Upadtes a Gnosis safe for given chain type. If no `backup_owner` is provided, it will assume a null value, that is, it will remove the backup owner from the safe.
Request @@ -290,7 +290,7 @@ Upadtes a Gnosis safe for given chain type. ```js { "chain": Chain, - "backup_owner": "0x650e83Bc808B8f405A9aF7CF68644cc817e084A6" + "backup_owner": "0x650e83Bc808B8f405A9aF7CF68644cc817e084A6" // Optional. } ``` diff --git a/operate/cli.py b/operate/cli.py index 446363591..8918d4572 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -618,7 +618,7 @@ async def _update_safe(request: Request) -> t.List[t.Dict]: wallet = manager.load(ledger_type=ledger_type) backup_owner_updated = wallet.update_backup_owner( chain=chain, - backup_owner=data.get("backup_owner"), + backup_owner=data.get("backup_owner"), # Optional value, it's fine to return None ) message = ( "Backup owner updated." From 8af9e3041a55dcc751268b392eff9f6a65754bbd Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 13:27:14 +0000 Subject: [PATCH 360/463] refactor: integrate services into YourWalletPage and enhance token symbol handling --- frontend/components/YourWalletPage/Titles.tsx | 20 +- .../components/YourWalletPage/YourAgent.tsx | 204 ++++++++++-------- frontend/components/YourWalletPage/index.tsx | 15 +- 3 files changed, 132 insertions(+), 107 deletions(-) diff --git a/frontend/components/YourWalletPage/Titles.tsx b/frontend/components/YourWalletPage/Titles.tsx index 4b2c7645f..4cea44cc9 100644 --- a/frontend/components/YourWalletPage/Titles.tsx +++ b/frontend/components/YourWalletPage/Titles.tsx @@ -1,6 +1,7 @@ import { Flex, Typography } from 'antd'; import { InfoTooltip } from '@/components/InfoTooltip'; +import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; import { AddressLink } from '../AddressLink'; @@ -17,8 +18,8 @@ export const SignerTitle = ({ Signer  - Your wallet and agent’s wallet use Safe, a multi-signature wallet. The - app is designed to trigger transactions on these Safe wallets via + Your wallet and agent's wallet use Safe, a multi-signature wallet. + The app is designed to trigger transactions on these Safe wallets via Signers. @@ -43,23 +44,24 @@ export const OlasTitle = () => ( Agent rewards accumulate in the staking contract. The agent is designed - to claim rewards periodically. Withdrawal of claimed rewards isn’t + to claim rewards periodically. Withdrawal of claimed rewards isn't available yet. ); -export const XdaiTitle = () => ( +export const NativeTokenTitle = ({ symbol }: { symbol: TokenSymbol }) => ( - XDAI + {symbol}   + {/* TODO: address multi-agent tooltip, specfic to agent config */} - XDAI is used by the agent to engage in prediction markets. This amount - will fluctuate based on your agent’s performance. + {symbol} is used by the agent to engage in prediction markets. This + amount will fluctuate based on your agent's performance. @@ -75,7 +77,7 @@ export const OwnershipNftTitle = () => ( Agents are minted through the Olas Registry. Each agent has an NFT - that gives its owner control over the agent’s settings. + that gives its owner control over the agent's settings. @@ -88,7 +90,7 @@ export const ServiceIdTitle = () => ( Each minted agent gets a unique ID. Technically, agents are referred to - as ‘services’. + as 'services'. diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index c0923e2ee..9910b02f3 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -1,15 +1,22 @@ import { Card, Flex, Skeleton, Tooltip, Typography } from 'antd'; +import { isEmpty, isNil } from 'lodash'; import Image from 'next/image'; import { useMemo } from 'react'; import styled from 'styled-components'; -import { MiddlewareChain } from '@/client'; -import { SERVICE_REGISTRY_L2_CONTRACT_ADDRESS } from '@/config/olasContracts'; +import { OLAS_CONTRACTS } from '@/config/olasContracts'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { useAddress } from '@/hooks/backup/useAddress'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { ChainId } from '@/enums/Chain'; +import { ContractType } from '@/enums/Contract'; +import { TokenSymbol } from '@/enums/Token'; +import { AgentSafe } from '@/enums/Wallet'; +import { + useBalanceContext, + useServiceBalances, +} from '@/hooks/useBalanceContext'; import { useReward } from '@/hooks/useReward'; -import { useServices } from '@/hooks/useServices'; +import { useService } from '@/hooks/useService'; +import { Address } from '@/types/Address'; import { generateName } from '@/utils/agentName'; import { balanceFormat } from '@/utils/numberFormatters'; import { truncateAddress } from '@/utils/truncate'; @@ -17,13 +24,7 @@ import { truncateAddress } from '@/utils/truncate'; import { AddressLink } from '../AddressLink'; import { InfoBreakdownList } from '../InfoBreakdown'; import { Container, infoBreakdownParentStyle } from './styles'; -import { - OlasTitle, - OwnershipNftTitle, - ServiceIdTitle, - SignerTitle, - XdaiTitle, -} from './Titles'; +import { OlasTitle, OwnershipNftTitle, ServiceIdTitle } from './Titles'; const { Text, Paragraph } = Typography; @@ -56,12 +57,10 @@ const SafeAddress = () => { ); }; -const AgentTitle = () => { - const { multisigAddress: agentSafeAddress } = useAddress(); - +const AgentTitle = ({ serviceSafe }: { serviceSafe: AgentSafe }) => { const agentName = useMemo( - () => (agentSafeAddress ? generateName(agentSafeAddress) : '--'), - [agentSafeAddress], + () => (serviceSafe ? generateName(serviceSafe.address) : '--'), + [serviceSafe], ); return ( @@ -83,22 +82,21 @@ const AgentTitle = () => { arrow={false} title={ - This is your agent’s unique name + This is your agent's unique name } placement="top" > {agentName} - {/* - ONLY APPLIES TO PREDICT AGENT + {/* TODO: address multi-agent at later point */} Agent profile {UNICODE_SYMBOLS.EXTERNAL_LINK} - */} + @@ -106,10 +104,13 @@ const AgentTitle = () => { ); }; -const ServiceAndNftDetails = () => { - const { serviceId } = useServices(); - const serviceAddress = - SERVICE_REGISTRY_L2_CONTRACT_ADDRESS[`${MiddlewareChain.OPTIMISM}`]; +const ServiceAndNftDetails = ({ + serviceConfigId, +}: { + serviceConfigId: string; +}) => { + const serviceRegistryL2ContractAddress = + OLAS_CONTRACTS[ChainId.Gnosis][ContractType.ServiceRegistryL2].address; return ( @@ -126,20 +127,21 @@ const ServiceAndNftDetails = () => { - {truncateAddress(serviceAddress)} {UNICODE_SYMBOLS.EXTERNAL_LINK} + {truncateAddress(serviceRegistryL2ContractAddress as Address)}{' '} + {UNICODE_SYMBOLS.EXTERNAL_LINK} - {serviceId} {UNICODE_SYMBOLS.EXTERNAL_LINK} + {serviceConfigId} {UNICODE_SYMBOLS.EXTERNAL_LINK} @@ -148,88 +150,100 @@ const ServiceAndNftDetails = () => { ); }; -export const YourAgentWallet = () => { - const { isBalanceLoaded, agentSafeBalance, agentEoaBalance } = - useBalanceContext(); +export const YourAgentWallet = ({ + serviceConfigId, +}: { + serviceConfigId: string; +}) => { + const { isLoaded } = useBalanceContext(); + const { serviceEoa, serviceSafes } = useService({ serviceConfigId }); + const { serviceSafeBalances, serviceEoaBalances, serviceStakedBalances } = + useServiceBalances(serviceConfigId); + const { availableRewardsForEpochEth, isEligibleForRewards, - accruedServiceStakingRewards, + accruedServiceStakingRewards, //TODO: determine where this is used } = useReward(); - const { instanceAddress: agentEoaAddress } = useAddress(); + // TODO: determine where this is used const reward = useMemo(() => { - if (!isBalanceLoaded) return ; + if (!isLoaded) return ; if (!isEligibleForRewards) return 'Not yet earned'; return `~${balanceFormat(availableRewardsForEpochEth, 2)} OLAS`; - }, [isBalanceLoaded, isEligibleForRewards, availableRewardsForEpochEth]); - - const olasBalances = useMemo(() => { - return [ - { - title: 'Claimed rewards', - value: `${balanceFormat(agentSafeBalance?.OLAS, 2)} OLAS`, - }, - { - title: 'Unclaimed rewards', - value: `${balanceFormat(accruedServiceStakingRewards, 2)} OLAS`, - }, - { - title: 'Current epoch rewards', - value: reward, - }, - ]; - }, [agentSafeBalance?.OLAS, accruedServiceStakingRewards, reward]); + }, [isLoaded, isEligibleForRewards, availableRewardsForEpochEth]); + + const serviceSafeOlasBalances = useMemo( + () => + serviceSafeBalances?.filter( + (balance) => balance.symbol === TokenSymbol.OLAS, + ), + [serviceSafeBalances], + ); + + const serviceSafeNativeBalances = useMemo( + () => serviceSafeBalances?.filter((balance) => balance.isNative), + [serviceSafeBalances], + ); + + const serviceEoaNativeBalances = useMemo( + () => serviceEoaBalances?.filter((balance) => balance.isNative), + [serviceEoaBalances], + ); + + const serviceSafe = useMemo(() => { + if (isNil(serviceSafes) || isEmpty(serviceSafes)) return null; + return serviceSafes[0]; + }, [serviceSafes]); return ( - }> + }> - - - ({ - left: item.title, - leftClassName: 'text-light text-sm', - right: item.value, - }))} - parentStyle={infoBreakdownParentStyle} - /> - - - - , + {!isEmpty(serviceSafeOlasBalances) && ( + + + ({ + left: item.symbol, leftClassName: 'text-light text-sm', - right: `${balanceFormat(agentSafeBalance?.ETH, 2)} XDAI`, - }, - ]} - parentStyle={infoBreakdownParentStyle} - /> - + right: item.balance, + }))} + parentStyle={infoBreakdownParentStyle} + /> + + )} - - - ), + {!isEmpty(serviceStakedBalances) && ( + + ({ + left: balance.symbol, leftClassName: 'text-light text-sm', - right: `${balanceFormat(agentEoaBalance?.ETH, 2)} XDAI`, - }, - ]} - parentStyle={infoBreakdownParentStyle} - /> - + right: `${balanceFormat(balance.balance, 2)} ${balance.symbol}`, + }))} + parentStyle={infoBreakdownParentStyle} + /> + + )} + + {serviceEoa?.address && !isEmpty(serviceEoaNativeBalances) && ( + + ({ + left: balance.symbol, + leftClassName: 'text-light text-sm', + right: `${balanceFormat(balance.balance, 2)} ${balance.symbol}`, + })) ?? [] + } + parentStyle={infoBreakdownParentStyle} + /> + + )} - + ); diff --git a/frontend/components/YourWalletPage/index.tsx b/frontend/components/YourWalletPage/index.tsx index d63aa58c4..47a2a433e 100644 --- a/frontend/components/YourWalletPage/index.tsx +++ b/frontend/components/YourWalletPage/index.tsx @@ -23,6 +23,7 @@ import { useMasterBalances, } from '@/hooks/useBalanceContext'; import { usePageState } from '@/hooks/usePageState'; +import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { type Address } from '@/types/Address'; import { Optional } from '@/types/Util'; @@ -164,9 +165,9 @@ const MasterEoaSignerNativeBalance = () => { }, [masterEoa, masterWalletBalances]); const nativeTokenSymbol = useMemo( - () => getNativeTokenSymbol(ChainId.Gnosis), + () => getNativeTokenSymbol(ChainId.Gnosis), // TODO: support multi chain [], - ); // TODO: support multi chain + ); return ( @@ -192,6 +193,8 @@ const MasterEoaSignerNativeBalance = () => { export const YourWalletPage = () => { const { goto } = usePageState(); + const { services } = useServices(); + return ( { - + {services?.map(({ service_config_id }) => ( + // TODO: bit dirty, but should be fine for now + + ))} From 9b68d8631ebb8419dbcc2ed718b6fd179297a8df Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 13:28:32 +0000 Subject: [PATCH 361/463] refactor: update comment formatting for accruedServiceStakingRewards in YourAgentWallet --- frontend/components/YourWalletPage/YourAgent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index 9910b02f3..3bdadc5e7 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -163,7 +163,7 @@ export const YourAgentWallet = ({ const { availableRewardsForEpochEth, isEligibleForRewards, - accruedServiceStakingRewards, //TODO: determine where this is used + accruedServiceStakingRewards, // TODO: determine where this is used } = useReward(); // TODO: determine where this is used From a2d4ae29f35d6d0c5b0cb74356acedf6f807f97f Mon Sep 17 00:00:00 2001 From: Mohan Date: Fri, 22 Nov 2024 18:58:37 +0530 Subject: [PATCH 362/463] refactor: Rewards History (#486) * refactor: rename isBalanceLoaded to isLoaded in RewardsSection * feat: update reward display to use NA constant and refactor balance loading state * feat: refactor RewardsHistory to use active staking program and improve service handling * feat: refactor useRewardsHistory to improve service handling and integrate chainId * refactor: update StakingProgramProvider to use service data and improve active staking program retrieval * refactor: consolidate service handling in StakingContractDetailsProvider and remove useServiceId hook * Update frontend/hooks/useRewardsHistory.ts Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> * Update frontend/context/StakingContractDetailsProvider.tsx Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> --------- Co-authored-by: Josh Miller <31908788+truemiller@users.noreply.github.com> --- .../RewardsHistory/RewardsHistory.tsx | 81 +++++++++++-------- .../StakingContractDetailsProvider.tsx | 14 +++- frontend/context/StakingProgramProvider.tsx | 20 +++-- frontend/hooks/useRewardsHistory.ts | 24 ++++-- frontend/hooks/useService.ts | 19 ----- 5 files changed, 89 insertions(+), 69 deletions(-) diff --git a/frontend/components/RewardsHistory/RewardsHistory.tsx b/frontend/components/RewardsHistory/RewardsHistory.tsx index e29fd43da..2e294f11b 100644 --- a/frontend/components/RewardsHistory/RewardsHistory.tsx +++ b/frontend/components/RewardsHistory/RewardsHistory.tsx @@ -22,15 +22,15 @@ import styled from 'styled-components'; import { MiddlewareChain } from '@/client'; import { CardTitle } from '@/components/Card/CardTitle'; import { CardFlex } from '@/components/styled/CardFlex'; -import { SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES } from '@/config/olasContracts'; +import { STAKING_PROGRAM_ADDRESS } from '@/config/stakingPrograms'; import { COLOR } from '@/constants/colors'; -import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { EXPLORER_URL } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; import { StakingProgramId } from '@/enums/StakingProgram'; import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; import { balanceFormat } from '@/utils/numberFormatters'; import { formatToMonthDay, formatToShortDateTime } from '@/utils/time'; @@ -148,42 +148,45 @@ type ContractRewardsProps = { checkpoints: Checkpoint[]; }; -const ContractRewards = ({ - stakingProgramId, - checkpoints, -}: ContractRewardsProps) => ( - - - {STAKING_PROGRAM_META[stakingProgramId].name} - +const ContractRewards = ({ checkpoints }: ContractRewardsProps) => { + const { activeStakingProgramMeta } = useStakingProgram(); - {checkpoints.map((checkpoint) => { - const currentEpochReward = checkpoint.reward - ? `~${balanceFormat(checkpoint.reward ?? 0, 2)} OLAS` - : '0 OLAS'; + return ( + + + {activeStakingProgramMeta?.name} + - return ( - - - - - - {currentEpochReward} - - - {checkpoint.earned ? : } - - - ); - })} - -); + {checkpoints.map((checkpoint) => { + const currentEpochReward = checkpoint.reward + ? `~${balanceFormat(checkpoint.reward ?? 0, 2)} OLAS` + : '0 OLAS'; + + return ( + + + + + + {currentEpochReward} + + + {checkpoint.earned ? : } + + + ); + })} + + ); +}; export const RewardsHistory = () => { const { contractCheckpoints, isError, isLoading, isFetching, refetch } = useRewardsHistory(); const { goto } = usePageState(); - const { serviceId } = useServices(); + const { selectedService } = useServices(); + const serviceId = selectedService?.service_config_id; + const chainId = selectedService?.home_chain_id; const history = useMemo(() => { if (isLoading || isFetching || !serviceId) return ; @@ -210,14 +213,14 @@ export const RewardsHistory = () => { }, ); + if (!chainId) return null; + return ( {latestContractAddresses.map((contractAddress: string) => { const checkpoints = contractCheckpoints[contractAddress]; const [stakingProgramId] = Object.entries( - SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[ - MiddlewareChain.OPTIMISM - ], + STAKING_PROGRAM_ADDRESS[chainId], ).find((entry) => { const [, stakingProxyAddress] = entry; return ( @@ -238,7 +241,15 @@ export const RewardsHistory = () => { })} ); - }, [isLoading, isFetching, isError, serviceId, contractCheckpoints, refetch]); + }, [ + isLoading, + isFetching, + isError, + serviceId, + chainId, + contractCheckpoints, + refetch, + ]); return ( diff --git a/frontend/context/StakingContractDetailsProvider.tsx b/frontend/context/StakingContractDetailsProvider.tsx index 9b14e13d3..62befaa50 100644 --- a/frontend/context/StakingContractDetailsProvider.tsx +++ b/frontend/context/StakingContractDetailsProvider.tsx @@ -13,7 +13,7 @@ import { import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useServiceId } from '@/hooks/useService'; +import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { StakingContractDetails } from '@/types/Autonolas'; @@ -132,7 +132,17 @@ export const StakingContractDetailsProvider = ({ children, }: PropsWithChildren) => { const [isPaused, setIsPaused] = useState(false); - const serviceId = useServiceId(); + const { + selectedService, + selectedAgentConfig, + isFetched: isLoaded, + } = useServices(); + const serviceConfigId = + selectedService?.service_config_id; + const { service } = useService({ serviceConfigId }); + const serviceId = + service?.chain_configs?.[selectedAgentConfig?.homeChainId]?.chain_data + ?.token; const { activeStakingProgramId } = useContext(StakingProgramContext); const { diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index ff283dab8..f26aedb42 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -5,7 +5,7 @@ import { INITIAL_DEFAULT_STAKING_PROGRAM_IDS } from '@/config/stakingPrograms'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { useServiceId } from '@/hooks/useService'; +import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { Maybe, Nullable } from '@/types/Util'; @@ -22,10 +22,9 @@ export const StakingProgramContext = createContext<{ /** * hook to get the active staking program id */ -const useGetActiveStakingProgramId = () => { +const useGetActiveStakingProgramId = (serviceId: Maybe) => { const queryClient = useQueryClient(); const { selectedAgentConfig } = useServices(); - const serviceId = useServiceId(); const { serviceApi, homeChainId } = selectedAgentConfig; @@ -68,9 +67,20 @@ const useGetActiveStakingProgramId = () => { * It also provides a method to update the active staking program id in state. */ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { - const { selectedAgentConfig } = useServices(); + const { + selectedService, + selectedAgentConfig, + isFetched: isLoaded, + } = useServices(); + const serviceConfigId = + isLoaded && selectedService ? selectedService?.service_config_id : ''; + const { service } = useService({ serviceConfigId }); + + // fetch chain data from the selected service + const chainId = selectedService?.home_chain_id; + const chainData = chainId ? service?.chain_configs[chainId].chain_data : null; const { isLoading: isStakingProgramsLoading, data: activeStakingProgramId } = - useGetActiveStakingProgramId(); + useGetActiveStakingProgramId(chainData?.token); return ( { - const serviceId = useServiceId(); - const { selectedAgentConfig } = useServices(); - const { homeChainId: chainId } = selectedAgentConfig; - +const useContractCheckpoints = (chainId: ChainId, serviceId: Maybe) => { const transformCheckpoints = useTransformCheckpoints(); return useQuery({ @@ -235,14 +233,24 @@ const useContractCheckpoints = () => { }; export const useRewardsHistory = () => { - const serviceId = useServiceId(); + const { + selectedService, + selectedAgentConfig, + isFetched: isLoaded, + } = useServices(); + const { homeChainId } = selectedAgentConfig; + const serviceConfigId = + selectedService?.service_config_id; + const { service } = useService({ serviceConfigId }); + const serviceId = service?.chain_configs[homeChainId].chain_data?.token; + const { isError, isLoading, isFetching, refetch, data: contractCheckpoints, - } = useContractCheckpoints(); + } = useContractCheckpoints(homeChainId, serviceId); const epochSortedCheckpoints = useMemo( () => diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index b0d2ec685..b6b6abfe3 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -172,22 +172,3 @@ export const useService = ({ isServiceBuilding, }; }; - -// TODO: support multiple services -/** - * Hook to get service id - */ -export const useServiceId = () => { - const { - selectedService, - selectedAgentConfig, - isFetched: isLoaded, - } = useServices(); - const { homeChainId } = selectedAgentConfig; - const serviceConfigId = - isLoaded && selectedService ? selectedService?.service_config_id : ''; - const { service } = useService({ serviceConfigId }); - const serviceId = service?.chain_configs[homeChainId].chain_data?.token; - - return serviceId; -}; From 5283e18eaaaa176cd0cd01500df5b3e57e031bca Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 13:55:04 +0000 Subject: [PATCH 363/463] refactor: enhance YourAgentWallet to include serviceSafeRewards and improve reward display --- .../components/YourWalletPage/YourAgent.tsx | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index 3bdadc5e7..529869ec7 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -181,6 +181,25 @@ export const YourAgentWallet = ({ [serviceSafeBalances], ); + // TODO: refactor for multichain/agent + const serviceSafeRewards = useMemo( + () => [ + { + title: 'Claimed rewards', + value: `${balanceFormat(serviceSafeOlasBalances?.[0].balance ?? 0, 2)} OLAS`, + }, + { + title: 'Unclaimed rewards', + value: `${balanceFormat(accruedServiceStakingRewards, 2)} OLAS`, + }, + { + title: 'Current epoch rewards', + value: reward, + }, + ], + [accruedServiceStakingRewards, reward, serviceSafeOlasBalances], + ); + const serviceSafeNativeBalances = useMemo( () => serviceSafeBalances?.filter((balance) => balance.isNative), [serviceSafeBalances], @@ -201,14 +220,14 @@ export const YourAgentWallet = ({ - {!isEmpty(serviceSafeOlasBalances) && ( + {!isEmpty(serviceSafeRewards) && ( ({ - left: item.symbol, + list={serviceSafeRewards.map((item) => ({ + left: item.title, leftClassName: 'text-light text-sm', - right: item.balance, + right: item.value, }))} parentStyle={infoBreakdownParentStyle} /> From daa1256c66e9e631325f02e86cee4e65a4b8be04 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 13:56:49 +0000 Subject: [PATCH 364/463] refactor: clean up unused comment for accruedServiceStakingRewards in YourAgentWallet --- frontend/components/YourWalletPage/YourAgent.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index 529869ec7..e792808b0 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -163,10 +163,9 @@ export const YourAgentWallet = ({ const { availableRewardsForEpochEth, isEligibleForRewards, - accruedServiceStakingRewards, // TODO: determine where this is used + accruedServiceStakingRewards, } = useReward(); - // TODO: determine where this is used const reward = useMemo(() => { if (!isLoaded) return ; if (!isEligibleForRewards) return 'Not yet earned'; From 8074c9d940826456a4822875273c4c541f203749 Mon Sep 17 00:00:00 2001 From: jmoreira-valory Date: Fri, 22 Nov 2024 14:58:06 +0100 Subject: [PATCH 365/463] fix: linters --- operate/cli.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/operate/cli.py b/operate/cli.py index 8918d4572..ad7ae745a 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -618,7 +618,9 @@ async def _update_safe(request: Request) -> t.List[t.Dict]: wallet = manager.load(ledger_type=ledger_type) backup_owner_updated = wallet.update_backup_owner( chain=chain, - backup_owner=data.get("backup_owner"), # Optional value, it's fine to return None + backup_owner=data.get( + "backup_owner" + ), # Optional value, it's fine to provide 'None' (set no backup owner/remove backup owner) ) message = ( "Backup owner updated." From 23d8990d71519f5ff15a39a574a7c59895f4a50a Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 14:40:46 +0000 Subject: [PATCH 366/463] refactor: bulk rename to remove "Optimus" from various files --- .github/workflows/release.yml | 2 +- build-win-tenderly.js | 2 +- build-win.js | 2 +- build.js | 2 +- build.tester.js | 2 +- electron/components/PearlTray.js | 2 +- electron/install.js | 6 +++--- electron/main.js | 6 +++--- package.json | 2 +- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a0ec9877d..29a43d323 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -110,7 +110,7 @@ jobs: # Download the appropriate architecture artifact - - name: Download Pearl (Optimus) binary for architecture + - name: Download Pearl binary for architecture uses: actions/download-artifact@v4 with: name: pearl_${{ matrix.arch }} diff --git a/build-win-tenderly.js b/build-win-tenderly.js index 80f7f0f7f..ddf660c8d 100644 --- a/build-win-tenderly.js +++ b/build-win-tenderly.js @@ -15,7 +15,7 @@ const main = async () => { config: { appId: 'xyz.valory.olas-pearl-optimus', artifactName: '${productName}-${version}-${platform}-${arch}-tenderly.${ext}', - productName: 'Pearl (Optimus)', + productName: 'Pearl', files: ['electron/**/*', 'package.json'], directories: { output: 'dist', diff --git a/build-win.js b/build-win.js index 6c595939b..870394446 100644 --- a/build-win.js +++ b/build-win.js @@ -22,7 +22,7 @@ const main = async () => { config: { appId: 'xyz.valory.olas-pearl-optimus', artifactName: artifactName(), - productName: 'Pearl (Optimus)', + productName: 'Pearl', files: ['electron/**/*', 'package.json'], directories: { output: 'dist', diff --git a/build.js b/build.js index 558847e93..d15fe5de7 100644 --- a/build.js +++ b/build.js @@ -25,7 +25,7 @@ const main = async () => { config: { appId: 'xyz.valory.olas-pearl-optimus', artifactName: artifactName(), - productName: 'Pearl (Optimus)', + productName: 'Pearl', files: ['electron/**/*', 'package.json'], directories: { output: 'dist', diff --git a/build.tester.js b/build.tester.js index a76d1c29e..68b53361c 100644 --- a/build.tester.js +++ b/build.tester.js @@ -18,7 +18,7 @@ const main = async () => { config: { appId: 'xyz.valory.olas-pearl-optimus', artifactName: '${productName}-${version}-${platform}-${arch}.${ext}', - productName: 'Pearl (Optimus)', + productName: 'Pearl', files: ['electron/**/*', 'package.json'], directories: { output: 'dist', diff --git a/electron/components/PearlTray.js b/electron/components/PearlTray.js index c28a571ae..506bea300 100644 --- a/electron/components/PearlTray.js +++ b/electron/components/PearlTray.js @@ -67,7 +67,7 @@ class PearlTray extends Electron.Tray { this.activeWindowCallback = activeWindowCallback; this.setContextMenu(new PearlTrayContextMenu(activeWindowCallback)); - this.setToolTip('Pearl (Optimus)'); + this.setToolTip('Pearl'); this.#bindClickEvents(); this.#bindIpcListener(); diff --git a/electron/install.js b/electron/install.js index 886301a2e..0d1aafa6e 100644 --- a/electron/install.js +++ b/electron/install.js @@ -29,7 +29,7 @@ const Env = { }; const SudoOptions = { - name: 'Pearl (Optimus)', + name: 'Pearl', env: Env, }; @@ -231,7 +231,7 @@ async function setupDarwin(ipcChannel) { logger.electron('Checking tendermint installation'); if (!isTendermintInstalledUnix()) { - ipcChannel.send('response', 'Installing Pearl (Optimus) Daemon'); + ipcChannel.send('response', 'Installing Pearl Daemon'); logger.electron('Installing tendermint'); await installTendermintUnix(); } @@ -245,7 +245,7 @@ async function setupUbuntu(ipcChannel) { logger.electron('Checking tendermint installation'); if (!isTendermintInstalledUnix()) { - ipcChannel.send('response', 'Installing Pearl (Optimus) Daemon'); + ipcChannel.send('response', 'Installing Pearl Daemon'); logger.electron('Installing tendermint'); await installTendermintUnix(); } diff --git a/electron/main.js b/electron/main.js index be2c0de11..ca61021ef 100644 --- a/electron/main.js +++ b/electron/main.js @@ -182,7 +182,7 @@ const createSplashWindow = () => { height: APP_WIDTH, resizable: false, show: true, - title: 'Pearl (Optimus)', + title: 'Pearl', frame: false, webPreferences: { nodeIntegration: true, @@ -203,7 +203,7 @@ const HEIGHT = 700; const createMainWindow = async () => { const width = isDev ? 840 : APP_WIDTH; mainWindow = new BrowserWindow({ - title: 'Pearl (Optimus)', + title: 'Pearl', resizable: false, draggable: true, frame: false, @@ -458,7 +458,7 @@ ipcMain.on('check', async function (event, _argument) { if (isDev) { event.sender.send( 'response', - 'Starting Pearl (Optimus) Daemon In Development Mode', + 'Starting Pearl Daemon In Development Mode', ); const daemonDevPortAvailable = await isPortAvailable( diff --git a/package.json b/package.json index b10340933..e80278bab 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ }, "main": "electron/main.js", "name": "olas-operate-app", - "productName": "Pearl (Optimus)", + "productName": "Pearl", "description": "An all-in-one application designed to streamline your entry into the world of autonomous agents and earning OLAS through staking.", "scripts": { "build:frontend": "cd frontend && yarn build && rm -rf ../electron/.next && cp -r .next ../electron/.next && rm -rf ../electron/public && cp -r public ../electron/public", From e8f8a304c9e96608e14c1ceeb0ecd72cee687052 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 14:42:07 +0000 Subject: [PATCH 367/463] refactor: update appId from "optimus" to "operate-app" in build scripts --- build-win-tenderly.js | 2 +- build-win.js | 2 +- build.js | 2 +- build.tester.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/build-win-tenderly.js b/build-win-tenderly.js index ddf660c8d..e98e3e5aa 100644 --- a/build-win-tenderly.js +++ b/build-win-tenderly.js @@ -13,7 +13,7 @@ const main = async () => { await build({ publish: 'onTag', config: { - appId: 'xyz.valory.olas-pearl-optimus', + appId: 'xyz.valory.olas-operate-app', artifactName: '${productName}-${version}-${platform}-${arch}-tenderly.${ext}', productName: 'Pearl', files: ['electron/**/*', 'package.json'], diff --git a/build-win.js b/build-win.js index 870394446..17920c4d2 100644 --- a/build-win.js +++ b/build-win.js @@ -20,7 +20,7 @@ const main = async () => { await build({ publish: 'onTag', config: { - appId: 'xyz.valory.olas-pearl-optimus', + appId: 'xyz.valory.olas-operate-app', artifactName: artifactName(), productName: 'Pearl', files: ['electron/**/*', 'package.json'], diff --git a/build.js b/build.js index d15fe5de7..d576ce904 100644 --- a/build.js +++ b/build.js @@ -23,7 +23,7 @@ const main = async () => { await build({ publish: 'onTag', config: { - appId: 'xyz.valory.olas-pearl-optimus', + appId: 'xyz.valory.olas-operate-app', artifactName: artifactName(), productName: 'Pearl', files: ['electron/**/*', 'package.json'], diff --git a/build.tester.js b/build.tester.js index 68b53361c..b4163427e 100644 --- a/build.tester.js +++ b/build.tester.js @@ -16,7 +16,7 @@ const main = async () => { await build({ publish: 'onTag', config: { - appId: 'xyz.valory.olas-pearl-optimus', + appId: 'xyz.valory.olas-operate-app', artifactName: '${productName}-${version}-${platform}-${arch}.${ext}', productName: 'Pearl', files: ['electron/**/*', 'package.json'], From 68785d551ae05a50194ecdad093c5423afcec565 Mon Sep 17 00:00:00 2001 From: truemiller Date: Fri, 22 Nov 2024 14:43:26 +0000 Subject: [PATCH 368/463] refactor: update download_binaries.sh to use trader version instead of optimus --- download_binaries.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/download_binaries.sh b/download_binaries.sh index 40a9572e6..0904caa13 100755 --- a/download_binaries.sh +++ b/download_binaries.sh @@ -4,8 +4,10 @@ BIN_DIR="electron/bins/" mkdir -p $BIN_DIR trader_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/trader.yaml')); print(config['service_version'])") -optimus_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/optimus.yaml')); print(config['service_version'])") +# optimus_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/optimus.yaml')); print(config['service_version'])") +# curl -L -o "${BIN_DIR}aea_bin_x64" "https://github.com/valory-xyz/optimus/releases/download/${optimus_version}/optimus_bin_x64" +# curl -L -o "${BIN_DIR}aea_bin_arm64" "https://github.com/valory-xyz/optimus/releases/download/${optimus_version}/optimus_bin_arm64" -curl -L -o "${BIN_DIR}aea_bin_x64" "https://github.com/valory-xyz/optimus/releases/download/${optimus_version}/optimus_bin_x64" -curl -L -o "${BIN_DIR}aea_bin_arm64" "https://github.com/valory-xyz/optimus/releases/download/${optimus_version}/optimus_bin_arm64" +curl -L -o "${BIN_DIR}aea_bin_x64" "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_x64" +curl -L -o "${BIN_DIR}aea_bin_arm64" "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_arm64" \ No newline at end of file From 02d9b5d9c1733f09d210b9d32a389c25be69edcd Mon Sep 17 00:00:00 2001 From: Atatakai Date: Fri, 22 Nov 2024 18:49:49 +0400 Subject: [PATCH 369/463] refactor: debug section --- .../SettingsPage/DebugInfoSection.tsx | 135 +++++++++--------- 1 file changed, 67 insertions(+), 68 deletions(-) diff --git a/frontend/components/SettingsPage/DebugInfoSection.tsx b/frontend/components/SettingsPage/DebugInfoSection.tsx index 14d2a7c26..83d934247 100644 --- a/frontend/components/SettingsPage/DebugInfoSection.tsx +++ b/frontend/components/SettingsPage/DebugInfoSection.tsx @@ -9,10 +9,10 @@ import { Tooltip, Typography, } from 'antd'; +import { isEmpty, isNil } from 'lodash'; import { useCallback, useMemo, useState } from 'react'; import styled from 'styled-components'; -import { MiddlewareChain } from '@/client'; import { COLOR } from '@/constants/colors'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { EXPLORER_URL } from '@/constants/urls'; @@ -21,8 +21,11 @@ import { WalletBalanceResult } from '@/context/BalanceProvider'; import { ChainId, ChainName } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; import { WalletType } from '@/enums/Wallet'; -import { useAddress } from '@/hooks/backup/useAddress'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { + useBalanceContext, + useMasterBalances, +} from '@/hooks/useBalanceContext'; +import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { Address } from '@/types/Address'; import { copyToClipboard } from '@/utils/copyToClipboard'; @@ -73,6 +76,8 @@ const DebugItem = ({ [item.address], ); + const chainIds = Object.keys(item.balance); + return ( @@ -105,22 +110,29 @@ const DebugItem = ({ </Col> <Col span={12}> - <Flex vertical gap={4} align="flex-start"> - <Text type="secondary" className="text-sm"> - Address - </Text> - <Flex gap={12}> - {/* <a - target="_blank" - href={`${EXPLORER_URL[MiddlewareChain.OPTIMISM]}/address/${item.address}`} - > */} - {truncatedAddress} - {/* </a> */} - <Tooltip title="Copy to clipboard"> - <CopyOutlined style={ICON_STYLE} onClick={onCopyToClipboard} /> - </Tooltip> + {chainIds.map((chainId) => ( + <Flex vertical gap={4} align="flex-start" key={chainId}> + <Text type="secondary" className="text-sm"> + Address{' '} + {chainIds.length > 1 && + `on ${ChainName[+chainId as keyof typeof ChainName]}`} + </Text> + <Flex gap={12}> + <a + target="_blank" + href={`${EXPLORER_URL[+chainId as keyof typeof EXPLORER_URL]}/address/${item.address}`} + > + {truncatedAddress} + </a> + <Tooltip title="Copy to clipboard"> + <CopyOutlined + style={ICON_STYLE} + onClick={onCopyToClipboard} + /> + </Tooltip> + </Flex> </Flex> - </Flex> + ))} </Col> </Row> {item.link ? ( @@ -135,24 +147,19 @@ const DebugItem = ({ }; export const DebugInfoSection = () => { - const { masterWallets: wallets } = useMasterWalletContext(); - const { instanceAddress, multisigAddress } = useAddress(); + const { masterEoa, masterSafes } = useMasterWalletContext(); + const { serviceAddresses } = useServices(); const { walletBalances } = useBalanceContext(); + const { masterEoaBalances, masterSafeBalances } = useMasterBalances(); const [isModalOpen, setIsModalOpen] = useState(false); const showModal = useCallback(() => setIsModalOpen(true), []); const handleCancel = useCallback(() => setIsModalOpen(false), []); - const masterEoas = wallets?.filter( - (wallet) => wallet.type === WalletType.EOA, - ); - - const masterSafes = wallets?.filter( - (wallet) => wallet.type === WalletType.Safe, - ); - const data = useMemo(() => { - if (!wallets?.length) return null; + if (isNil(masterEoa)) return null; + if (isNil(masterSafes) || isEmpty(masterSafes)) return null; + if (isNil(walletBalances) || isEmpty(walletBalances)) return null; const result: { title: string; @@ -161,58 +168,50 @@ export const DebugInfoSection = () => { link?: { title: string; href: string }; }[] = []; - masterEoas?.forEach((wallet) => { - result.push({ - title: 'Master EOA', - ...getBalanceData( - walletBalances.filter((walletBalanceResult) => { - return walletBalanceResult.walletAddress === wallet.address; - }), - ), - address: wallet.address, - }); + result.push({ + title: 'Master EOA', + ...getBalanceData(masterEoaBalances), + address: masterEoa.address, }); - masterSafes?.forEach((wallet) => { + masterSafes.forEach((wallet) => { result.push({ title: 'Master Safe', - ...getBalanceData( - walletBalances.filter((walletBalanceResult) => { - return walletBalanceResult.walletAddress === wallet.address; - }), - ), + ...getBalanceData(masterSafeBalances), address: wallet.address, - link: { - title: 'Go to Safe', - href: `${EXPLORER_URL[MiddlewareChain.OPTIMISM]}/address/${wallet.address}`, - }, }); }); - if (instanceAddress) { - result.push({ - title: 'Agent Instance EOA', - ...getBalanceData(walletBalances!), - address: instanceAddress, - }); - } - - if (multisigAddress) { - result.push({ - title: 'Agent Safe', - ...getBalanceData(walletBalances), - address: multisigAddress, - }); - } + serviceAddresses?.forEach((wallet) => { + if (wallet.type === WalletType.EOA) { + result.push({ + title: 'Agent Instance EOA', + ...getBalanceData( + walletBalances.filter( + (balance) => balance.walletAddress === wallet.address, + ), + ), + address: wallet.address, + }); + } + + if (wallet.type === WalletType.Safe) { + result.push({ + title: 'Agent Safe', + ...getBalanceData(walletBalances), + address: wallet.address, + }); + } + }); return result; }, [ - instanceAddress, - masterEoas, + masterEoa, + masterEoaBalances, + masterSafeBalances, masterSafes, - multisigAddress, + serviceAddresses, walletBalances, - wallets?.length, ]); return ( From 9141cf7329ef9a6d566653253fe90a43fb573d80 Mon Sep 17 00:00:00 2001 From: Mohan <mohandast52@gmail.com> Date: Fri, 22 Nov 2024 20:30:17 +0530 Subject: [PATCH 370/463] refactor: magic moment popup and few other components (#491) * refactor: update StakingProgramProvider to use service ID for fetching active staking program * refactor: clean up imports and enhance staking program handling in MainPage components --- frontend/components/MainPage/index.tsx | 34 +++++++++++-------- .../MainPage/sections/OlasBalanceSection.tsx | 12 +++---- .../sections/RewardsSection/index.tsx | 12 +++---- .../sections/StakingContractUpdate.tsx | 29 ++++++---------- frontend/context/RewardProvider.tsx | 14 +++++--- frontend/context/StakingProgramProvider.tsx | 6 ++-- frontend/hooks/useRewardsHistory.ts | 9 ++--- frontend/hooks/useStakingContractDetails.ts | 2 +- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index 7e444272d..c7c2997e1 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -2,10 +2,17 @@ import { QuestionCircleOutlined, SettingOutlined } from '@ant-design/icons'; import { Button, Card, Flex } from 'antd'; import { Pages } from '@/enums/Pages'; +import { StakingProgramId } from '@/enums/StakingProgram'; // import { StakingProgramId } from '@/enums/StakingProgram'; // import { useMasterSafe } from '@/hooks/useMasterSafe'; import { usePageState } from '@/hooks/usePageState'; +import { + useStakingContractContext, + useStakingContractDetails, +} from '@/hooks/useStakingContractDetails'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; +// import { useMasterWalletContext } from '@/hooks/useWallet'; import { MainHeader } from './header'; import { AddFundsSection } from './sections/AddFundsSection'; import { AlertSections } from './sections/AlertSections'; @@ -18,22 +25,22 @@ import { StakingContractUpdate } from './sections/StakingContractUpdate'; export const Main = () => { const { goto } = usePageState(); - // const { backupSafeAddress } = useMasterSafe(); + // const { backupSafeAddress } = useMasterWalletContext(); // const { refetch: updateServicesState } = useServices(); // const { // updateBalances, // isLoaded: isBalanceLoaded, // setIsLoaded: setIsBalanceLoaded, // } = useBalanceContext(); - // const { activeStakingProgramId } = useStakingProgram(); + const { activeStakingProgramId } = useStakingProgram(); // TODO: reintroduce later, non critical - // const { isAllStakingContractDetailsRecordLoaded } = - // useStakingContractContext(); + const { isAllStakingContractDetailsRecordLoaded } = + useStakingContractContext(); - // const { hasEnoughServiceSlots } = useStakingContractDetails( - // activeStakingProgramId, - // ); + const { hasEnoughServiceSlots } = useStakingContractDetails( + activeStakingProgramId, + ); // TODO: reintroduce later, non critical @@ -51,11 +58,11 @@ export const Main = () => { // TODO: reintroduce later, non critical - // const hideMainOlasBalanceTopBorder = [ - // !backupSafeAddress, // TODO: update this condition to check backup safe relative to selectedService - // activeStakingProgramId === StakingProgramId.Alpha, - // isAllStakingContractDetailsRecordLoaded && !hasEnoughServiceSlots, - // ].some((condition) => !!condition); + const hideMainOlasBalanceTopBorder = [ + // !backupSafeAddress, // TODO: update this condition to check backup safe relative to selectedService + activeStakingProgramId === StakingProgramId.PearlAlpha, + isAllStakingContractDetailsRecordLoaded && !hasEnoughServiceSlots, + ].some((condition) => !!condition); return ( <Card @@ -86,8 +93,7 @@ export const Main = () => { > <Flex vertical> <AlertSections /> - <MainOlasBalance isBorderTopVisible={false} /> - {/* <MainOlasBalance isBorderTopVisible={!hideMainOlasBalanceTopBorder} /> */} + <MainOlasBalance isBorderTopVisible={!hideMainOlasBalanceTopBorder} /> <RewardsSection /> <KeepAgentRunningSection /> <StakingContractUpdate /> diff --git a/frontend/components/MainPage/sections/OlasBalanceSection.tsx b/frontend/components/MainPage/sections/OlasBalanceSection.tsx index 5a7ca8aed..54558e345 100644 --- a/frontend/components/MainPage/sections/OlasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/OlasBalanceSection.tsx @@ -1,18 +1,18 @@ -// import { RightOutlined } from '@ant-design/icons'; +import { RightOutlined } from '@ant-design/icons'; import { Flex, Skeleton, Typography } from 'antd'; import { useMemo } from 'react'; import styled from 'styled-components'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { Pages } from '@/enums/Pages'; import { TokenSymbol } from '@/enums/Token'; -// import { Pages } from '@/enums/PageState'; import { useBalanceContext, useMasterBalances, useServiceBalances, } from '@/hooks/useBalanceContext'; +import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; -// import { usePageState } from '@/hooks/usePageState'; import { balanceFormat } from '@/utils/numberFormatters'; import { CardSection } from '../../styled/CardSection'; @@ -34,7 +34,7 @@ export const MainOlasBalance = ({ const { serviceStakedBalances, serviceWalletBalances } = useServiceBalances( selectedService?.service_config_id, ); - // const { goto } = usePageState(); + const { goto } = usePageState(); const displayedBalance = useMemo(() => { // olas across master wallets, safes and eoa @@ -92,14 +92,14 @@ export const MainOlasBalance = ({ <span className="balance-currency">OLAS</span> </Flex> - {/* <Text + <Text type="secondary" className="text-sm pointer hover-underline" onClick={() => goto(Pages.YourWalletBreakdown)} > See breakdown <RightOutlined style={{ fontSize: 12, paddingLeft: 6 }} /> - </Text> */} + </Text> </Flex> ) : ( <Skeleton.Input active size="large" style={{ margin: '4px 0' }} /> diff --git a/frontend/components/MainPage/sections/RewardsSection/index.tsx b/frontend/components/MainPage/sections/RewardsSection/index.tsx index aaee56c48..91c59671c 100644 --- a/frontend/components/MainPage/sections/RewardsSection/index.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/index.tsx @@ -1,12 +1,13 @@ import { Flex, Skeleton, Tag, Typography } from 'antd'; +import { NA } from '@/constants/symbols'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useReward } from '@/hooks/useReward'; import { balanceFormat } from '@/utils/numberFormatters'; import { CardSection } from '../../../styled/CardSection'; -// import { RewardsStreak } from './RewardsStreak'; -// import { NotifyRewardsModal } from './NotifyRewardsModal'; +import { NotifyRewardsModal } from './NotifyRewardsModal'; +import { RewardsStreak } from './RewardsStreak'; import { StakingRewardsThisEpoch } from './StakingRewardsThisEpoch'; const { Text } = Typography; @@ -19,12 +20,11 @@ const Loader = () => ( ); const getFormattedReward = (reward: number | undefined) => - reward === undefined ? '--' : `~${balanceFormat(reward, 2)}`; + reward === undefined ? NA : `~${balanceFormat(reward, 2)}`; const DisplayRewards = () => { const { availableRewardsForEpochEth, isEligibleForRewards } = useReward(); const { isLoaded } = useBalanceContext(); - const reward = getFormattedReward(availableRewardsForEpochEth); return ( @@ -55,7 +55,7 @@ const DisplayRewards = () => { export const RewardsSection = () => ( <> <DisplayRewards /> - {/* <RewardsStreak /> */} - {/* <NotifyRewardsModal /> */} + <RewardsStreak /> + <NotifyRewardsModal /> </> ); diff --git a/frontend/components/MainPage/sections/StakingContractUpdate.tsx b/frontend/components/MainPage/sections/StakingContractUpdate.tsx index a9d90532e..d49c6fea1 100644 --- a/frontend/components/MainPage/sections/StakingContractUpdate.tsx +++ b/frontend/components/MainPage/sections/StakingContractUpdate.tsx @@ -2,9 +2,9 @@ import { RightOutlined } from '@ant-design/icons'; import { Button, Flex, Skeleton, Typography } from 'antd'; import { useMemo } from 'react'; -import { DeploymentStatus } from '@/client'; -import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; -import { Pages } from '@/enums/PageState'; +import { MiddlewareDeploymentStatus } from '@/client'; +import { NA } from '@/constants/symbols'; +import { Pages } from '@/enums/Pages'; import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; import { useStakingContractContext } from '@/hooks/useStakingContractDetails'; @@ -16,28 +16,21 @@ const { Text } = Typography; export const StakingContractUpdate = () => { const { goto } = usePageState(); - const { - isActiveStakingProgramLoaded, - activeStakingProgramMeta, - defaultStakingProgramId, - } = useStakingProgram(); + const { isActiveStakingProgramLoaded, activeStakingProgramMeta } = + useStakingProgram(); const { isAllStakingContractDetailsRecordLoaded } = useStakingContractContext(); - const { serviceStatus } = useServices(); + const { selectedService } = useServices(); + const serviceStatus = selectedService?.deploymentStatus; const serviceIsTransitioning = useMemo( () => - serviceStatus === DeploymentStatus.DEPLOYING || - serviceStatus === DeploymentStatus.STOPPING, + serviceStatus === MiddlewareDeploymentStatus.DEPLOYING || + serviceStatus === MiddlewareDeploymentStatus.STOPPING, [serviceStatus], ); - const stakingContractName = useMemo(() => { - if (activeStakingProgramMeta) return activeStakingProgramMeta.name; - return STAKING_PROGRAM_META[DEFAULT_STAKING_PROGRAM_ID].name; - }, [activeStakingProgramMeta]); - const gotoManageStakingButton = useMemo(() => { if (!isActiveStakingProgramLoaded) return <Skeleton.Input />; return ( @@ -49,7 +42,7 @@ export const StakingContractUpdate = () => { !isAllStakingContractDetailsRecordLoaded || serviceIsTransitioning } > - {stakingContractName} + {activeStakingProgramMeta?.name || NA} <RightOutlined /> </Button> ); @@ -58,7 +51,7 @@ export const StakingContractUpdate = () => { isActiveStakingProgramLoaded, isAllStakingContractDetailsRecordLoaded, serviceIsTransitioning, - stakingContractName, + activeStakingProgramMeta?.name, ]); return ( diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index ec1c31deb..b39a78898 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -50,9 +50,8 @@ const useStakingRewardsDetails = () => { const { isOnline } = useContext(OnlineStatusContext); const { activeStakingProgramId } = useContext(StakingProgramContext); - const { selectedService, isFetched: isLoaded } = useServices(); - const serviceConfigId = - isLoaded && selectedService ? selectedService?.service_config_id : ''; + const { selectedService } = useServices(); + const serviceConfigId = selectedService?.service_config_id; const { service } = useService({ serviceConfigId }); // fetch chain data from the selected service @@ -63,7 +62,7 @@ const useStakingRewardsDetails = () => { return useQuery({ queryKey: REACT_QUERY_KEYS.REWARDS_KEY( currentChainId, - serviceConfigId, + serviceConfigId!, activeStakingProgramId!, multisig!, token!, @@ -79,7 +78,12 @@ const useStakingRewardsDetails = () => { ); return StakingRewardsInfoSchema.parse(response); }, - enabled: !!isOnline && !!activeStakingProgramId && !!multisig && !!token, + enabled: + !!isOnline && + !!serviceConfigId && + !!activeStakingProgramId && + !!multisig && + !!token, refetchInterval: isOnline ? FIVE_SECONDS_INTERVAL : false, refetchOnWindowFocus: false, }); diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index f26aedb42..073aad0a4 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -78,9 +78,11 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { // fetch chain data from the selected service const chainId = selectedService?.home_chain_id; - const chainData = chainId ? service?.chain_configs[chainId].chain_data : null; + const serviceId = chainId + ? service?.chain_configs[chainId].chain_data?.token + : null; const { isLoading: isStakingProgramsLoading, data: activeStakingProgramId } = - useGetActiveStakingProgramId(chainData?.token); + useGetActiveStakingProgramId(serviceId); return ( <StakingProgramContext.Provider diff --git a/frontend/hooks/useRewardsHistory.ts b/frontend/hooks/useRewardsHistory.ts index 483618339..392da9431 100644 --- a/frontend/hooks/useRewardsHistory.ts +++ b/frontend/hooks/useRewardsHistory.ts @@ -233,14 +233,9 @@ const useContractCheckpoints = (chainId: ChainId, serviceId: Maybe<number>) => { }; export const useRewardsHistory = () => { - const { - selectedService, - selectedAgentConfig, - isFetched: isLoaded, - } = useServices(); + const { selectedService, selectedAgentConfig } = useServices(); const { homeChainId } = selectedAgentConfig; - const serviceConfigId = - selectedService?.service_config_id; + const serviceConfigId = selectedService?.service_config_id; const { service } = useService({ serviceConfigId }); const serviceId = service?.chain_configs[homeChainId].chain_data?.token; diff --git a/frontend/hooks/useStakingContractDetails.ts b/frontend/hooks/useStakingContractDetails.ts index b0cd418f2..1b53630e7 100644 --- a/frontend/hooks/useStakingContractDetails.ts +++ b/frontend/hooks/useStakingContractDetails.ts @@ -31,7 +31,7 @@ export const useStakingContractContext = () => { /** * Returns ACTIVE staking contract details - * Has staked service speficic information that `useStakingContractDetails` does not have + * Has staked service specific information that `useStakingContractDetails` does not have * @note requires serviceConfigId once multiple instances are supported */ From 82b62e6a3cb363205f43c118c16ba6a04f03f543 Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Fri, 22 Nov 2024 15:38:59 +0000 Subject: [PATCH 371/463] refactor: update staking program handling and improve logs mapping --- .../components/ManageStakingPage/index.tsx | 19 ++++++++++--------- frontend/hooks/useLogs.ts | 7 ++++--- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index 10a798831..d46cd19c1 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,11 +1,11 @@ import { CloseOutlined } from '@ant-design/icons'; import { Button, Card } from 'antd'; -import { STAKING_PROGRAM_META } from '@/constants/stakingProgramMeta'; -import { DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider'; +import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { Pages } from '@/enums/Pages'; import { StakingProgramId } from '@/enums/StakingProgram'; import { usePageState } from '@/hooks/usePageState'; +import { useServices } from '@/hooks/useServices'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { CardTitle } from '../Card/CardTitle'; @@ -15,6 +15,7 @@ import { WhatAreStakingContractsSection } from './WhatAreStakingContracts'; export const ManageStakingPage = () => { const { goto } = usePageState(); + const { selectedAgentConfig } = useServices(); const { activeStakingProgramId } = useStakingProgram(); const orderedStakingProgramIds: StakingProgramId[] = Object.values( @@ -26,14 +27,13 @@ export const ManageStakingPage = () => { } // put default at the top if no activeStakingProgram - if ( - activeStakingProgramId === null && - stakingProgramId === DEFAULT_STAKING_PROGRAM_ID - ) - return [stakingProgramId, ...acc]; + if (activeStakingProgramId) return [stakingProgramId, ...acc]; // if the program is deprecated, ignore it - if (STAKING_PROGRAM_META[stakingProgramId]?.deprecated) { + if ( + STAKING_PROGRAMS[selectedAgentConfig.homeChainId][stakingProgramId] + .deprecated + ) { return acc; } @@ -43,7 +43,8 @@ export const ManageStakingPage = () => { const otherStakingProgramIds = orderedStakingProgramIds.filter( (stakingProgramId) => { - const info = STAKING_PROGRAM_META[stakingProgramId]; + const info = + STAKING_PROGRAMS[selectedAgentConfig.homeChainId][stakingProgramId]; if (!info) return false; if (activeStakingProgramId === stakingProgramId) return false; if (info.deprecated) return false; diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index 297247a80..e1d890209 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -28,13 +28,14 @@ const useAddressesLogs = () => { if (!allMasterSafeOwners) return; const result = allMasterSafeOwners - .map(({ owners }) => + .map((masterSafeOwners) => + masterSafeOwners.owners .filter((owner): owner is Address => owner !== masterEoa.address) .map<Eoa>((owner) => ({ address: owner, type: WalletType.EOA, - safeAddress: owners.safeAddress, - chainId: owners.chainId, + safeAddress: masterSafeOwners.safeAddress, + chainId: masterSafeOwners.chainId, })), ) .flat(); From 1c395c302d9517af4df1de847950481a6b994995 Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Fri, 22 Nov 2024 16:14:24 +0000 Subject: [PATCH 372/463] fix: quick fixes --- frontend/components/SetupPage/SetupWelcome.tsx | 7 ++++++- frontend/context/MasterWalletProvider.tsx | 2 +- frontend/utils/middlewareHelpers.ts | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/frontend/components/SetupPage/SetupWelcome.tsx b/frontend/components/SetupPage/SetupWelcome.tsx index 9c053d6e0..32ce62984 100644 --- a/frontend/components/SetupPage/SetupWelcome.tsx +++ b/frontend/components/SetupPage/SetupWelcome.tsx @@ -24,6 +24,7 @@ import { useServices } from '@/hooks/useServices'; import { useSetup } from '@/hooks/useSetup'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { AccountService } from '@/service/Account'; +import { convertMiddlewareChainToChainId } from '@/utils/middlewareHelpers'; import { FormFlex } from '../styled/FormFlex'; @@ -144,7 +145,10 @@ export const SetupWelcomeLogin = () => { const masterSafe = masterSafes?.find( - (safe) => safe.chainId === selectedService?.home_chain_id, + (safe) => + selectedService?.home_chain && + safe.chainId === + convertMiddlewareChainToChainId(selectedService?.home_chain), ) ?? null; const eoaBalanceEth = masterWalletBalances?.find( (balance) => balance.walletAddress === masterEoa?.address, @@ -176,6 +180,7 @@ export const SetupWelcomeLogin = () => { // To check if some setup steps were missed // if (canNavigate && wallets?.length && isBalanceLoaded) { + // TODO: fix wallet and balance loads if (canNavigate) { setIsLoggingIn(false); if (!eoaBalanceEth) { diff --git a/frontend/context/MasterWalletProvider.tsx b/frontend/context/MasterWalletProvider.tsx index e9a7b2778..55fa87925 100644 --- a/frontend/context/MasterWalletProvider.tsx +++ b/frontend/context/MasterWalletProvider.tsx @@ -45,7 +45,7 @@ const transformMiddlewareWalletResponse = ( const masterSafes: MasterSafe[] = Object.entries(data.safes).map( ([middlewareChain, address]) => ({ address, - chainId: convertMiddlewareChainToChainId(+middlewareChain), + chainId: convertMiddlewareChainToChainId(middlewareChain), owner: WalletOwnerType.Master, type: WalletType.Safe, }), diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts index 39fefab64..728c9fe95 100644 --- a/frontend/utils/middlewareHelpers.ts +++ b/frontend/utils/middlewareHelpers.ts @@ -8,7 +8,7 @@ import { ChainId } from '@/enums/Chain'; * @throws Error */ export const convertMiddlewareChainToChainId = ( - chain: MiddlewareChain, + chain: MiddlewareChain | string, ): ChainId => { switch (chain) { case MiddlewareChain.ETHEREUM: From 6831a66b4f0c02ab12e1059e0ab0e8cd0f8fc4af Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Fri, 22 Nov 2024 16:20:46 +0000 Subject: [PATCH 373/463] feat: integrate master wallet context and update multisig address retrieval --- frontend/components/MainPage/header/LastTransaction.tsx | 5 +++-- frontend/hooks/useService.ts | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/components/MainPage/header/LastTransaction.tsx b/frontend/components/MainPage/header/LastTransaction.tsx index 5ab251361..069a9a58d 100644 --- a/frontend/components/MainPage/header/LastTransaction.tsx +++ b/frontend/components/MainPage/header/LastTransaction.tsx @@ -9,6 +9,7 @@ import { EXPLORER_URL } from '@/constants/urls'; import { usePageState } from '@/hooks/usePageState'; import { useService } from '@/hooks/useService'; import { useStakingProgram } from '@/hooks/useStakingProgram'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { getLatestTransaction } from '@/service/Ethers'; import { TransactionInfo } from '@/types/TransactionInfo'; import { Optional } from '@/types/Util'; @@ -35,8 +36,8 @@ export const LastTransaction = ({ serviceConfigId }: LastTransactionProps) => { const { isPageLoadedAndOneMinutePassed } = usePageState(); const { activeStakingProgramMeta } = useStakingProgram(); const { service } = useService({ serviceConfigId }); - const multisigAddress = - service?.chain_configs[service?.home_chain_id].chain_data.multisig; + const { masterSafes } = useMasterWalletContext(); + const multisigAddress = masterSafe; const chainId = activeStakingProgramMeta?.chainId; const [isFetching, setIsFetching] = useState(true); diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index b6b6abfe3..de53bc8e8 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -2,6 +2,7 @@ import { useQueryClient } from '@tanstack/react-query'; import { useMemo } from 'react'; import { + MiddlewareBuildingStatuses, MiddlewareDeploymentStatus, MiddlewareRunningStatuses, MiddlewareTransitioningStatuses, From a86cdfdca11a79bb781a6e7d9b29c2cd36c24ced Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Fri, 22 Nov 2024 16:20:56 +0000 Subject: [PATCH 374/463] feat: chain conversion helper --- frontend/utils/middlewareHelpers.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts index 728c9fe95..cd32c1aaf 100644 --- a/frontend/utils/middlewareHelpers.ts +++ b/frontend/utils/middlewareHelpers.ts @@ -22,3 +22,17 @@ export const convertMiddlewareChainToChainId = ( } throw new Error(`Invalid middleware chain enum: ${chain}`); }; + +export const convertChainIdToMiddlewareChain = (chainId: ChainId | number) => { + switch (chainId) { + case ChainId.Ethereum: + return MiddlewareChain.ETHEREUM; + case ChainId.Optimism: + return MiddlewareChain.OPTIMISM; + case ChainId.Gnosis: + return MiddlewareChain.GNOSIS; + case ChainId.Base: + return MiddlewareChain.BASE; + } + throw new Error(`Invalid chain id: ${chainId}`); +}; From 858dd4768b73899611eba9de581cb1980f5932cb Mon Sep 17 00:00:00 2001 From: jmoreira-valory <jose.moreira.sanchez@valory.xyz> Date: Fri, 22 Nov 2024 18:08:51 +0100 Subject: [PATCH 375/463] chore: add enriched endpoint --- api.md | 59 ++++++++++++++++++++++++++++++++++++++++ operate/cli.py | 9 ++++++ operate/wallet/master.py | 31 +++++++++++++++++++++ 3 files changed, 99 insertions(+) diff --git a/api.md b/api.md index ab77b977f..38c160828 100644 --- a/api.md +++ b/api.md @@ -198,6 +198,65 @@ Returns a list of available wallets --- +### `GET /api/enriched/wallet` + +Returns a list of available wallets with enriched information. It executes on-chain requests to populate the list of owners of each safe, and provides the attributes `all_safe_backup_owners_match` and `single_safe_backup_owner_per_chain`. + +<details> + <summary>Response</summary> + +```json +[ + { + "address":"0xFafd5cb31a611C5e5aa65ea8c6226EB4328175E7", + "all_safe_backup_owners_match":false, + "ledger_type":"ethereum", + "safe_chains":[ + "gnosis", + "ethereum", + "base", + "optimistic" + ], + "safe_nonce":110558881674480320952254000342160989674913430251257716940579305238321962891821, + "safes":{ + "base":{ + "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23":{ + "owners":[ + + ] + } + }, + "ethereum":{ + "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23":{ + "owners":[ + "0x46eC2E77Fe3E367252f1A8a77470CE8eEd2A985b" + ] + } + }, + "gnosis":{ + "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23":{ + "owners":[ + "0x46eC2E77Fe3E367252f1A8a77470CE8eEd2A985b" + ] + } + }, + "optimistic":{ + "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23":{ + "owners":[ + "0x46eC2E77Fe3E367252f1A8a77470CE8eEd2A985b" + ] + } + } + }, + "single_safe_backup_owner_per_chain":false + } +] +``` + +</details> + +--- + ### `POST /api/wallet` Creates a master wallet for given chain type. If a wallet already exists for a given chain type, it returns the already existing wallet without creating an additional one. diff --git a/operate/cli.py b/operate/cli.py index ad7ae745a..af2af761a 100644 --- a/operate/cli.py +++ b/operate/cli.py @@ -447,6 +447,15 @@ async def _create_wallet(request: Request) -> t.List[t.Dict]: wallet, mnemonic = manager.create(ledger_type=ledger_type) return JSONResponse(content={"wallet": wallet.json, "mnemonic": mnemonic}) + @app.get("/api/enriched/wallet") + @with_retries + async def _get_wallet_safe(request: Request) -> t.List[t.Dict]: + """Get wallets.""" + wallets = [] + for wallet in operate.wallet_manager: + wallets.append(wallet.enriched_json) + return JSONResponse(content=wallets) + @app.get("/api/wallet/safe") @with_retries async def _get_safes(request: Request) -> t.List[t.Dict]: diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 17664103e..86a3cfee0 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -145,6 +145,12 @@ def update_backup_owner( """Update backup owner.""" raise NotImplementedError() + # TODO move to resource.py ? + @property + def enriched_json(self) -> t.Dict: + """Get JSON representation with extended information (e.g., safe owners).""" + raise NotImplementedError + @classmethod def migrate_format(cls, path: Path) -> bool: """Migrate the JSON file format if needed.""" @@ -393,6 +399,31 @@ def update_backup_owner( return False + @property + def enriched_json(self) -> t.Dict: + """Get JSON representation with extended information (e.g., safe owners).""" + rpc = None + wallet_json = self.json + + if not self.safes: + return wallet_json + + owner_sets = set() + for chain, safe in self.safes.items(): + ledger_api = self.ledger_api(chain=chain, rpc=rpc) + owners = get_owners(ledger_api=ledger_api, safe=safe) + owners.remove(self.address) + wallet_json["safes"][chain.value] = { + wallet_json["safes"][chain.value]: {"owners": owners} + } + owner_sets.add(frozenset(owners)) + + wallet_json["all_safe_backup_owners_match"] = len(owner_sets) == 1 + wallet_json["single_safe_backup_owner_per_chain"] = all( + len(owner) == 1 for owner in owner_sets + ) + return wallet_json + @classmethod def load(cls, path: Path) -> "EthereumMasterWallet": """Load master wallet.""" From 8e29636458e04d9894572b6236b261ff0e93bf07 Mon Sep 17 00:00:00 2001 From: jmoreira-valory <jose.moreira.sanchez@valory.xyz> Date: Fri, 22 Nov 2024 18:16:22 +0100 Subject: [PATCH 376/463] chore: doc --- api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.md b/api.md index 38c160828..e3fb97f1d 100644 --- a/api.md +++ b/api.md @@ -222,7 +222,7 @@ Returns a list of available wallets with enriched information. It executes on-ch "base":{ "0xd56fb274ce2C66008D5c4C09980c4f36Ab81ff23":{ "owners":[ - + // No owners for this safe ] } }, From 5842c863356357bc9f325b51c8791d1c306d4de6 Mon Sep 17 00:00:00 2001 From: jmoreira-valory <jose.moreira.sanchez@valory.xyz> Date: Fri, 22 Nov 2024 18:24:51 +0100 Subject: [PATCH 377/463] refactor: rename parameter --- api.md | 4 ++-- operate/wallet/master.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api.md b/api.md index e3fb97f1d..05b4cb5fe 100644 --- a/api.md +++ b/api.md @@ -200,7 +200,7 @@ Returns a list of available wallets ### `GET /api/enriched/wallet` -Returns a list of available wallets with enriched information. It executes on-chain requests to populate the list of owners of each safe, and provides the attributes `all_safe_backup_owners_match` and `single_safe_backup_owner_per_chain`. +Returns a list of available wallets with enriched information. It executes on-chain requests to populate the list of owners of each safe, and provides the attributes `all_safe_backup_owners_match` and `single_backup_owner_per_safe`. <details> <summary>Response</summary> @@ -248,7 +248,7 @@ Returns a list of available wallets with enriched information. It executes on-ch } } }, - "single_safe_backup_owner_per_chain":false + "single_backup_owner_per_safe":false } ] ``` diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 86a3cfee0..f7c058e1c 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -419,7 +419,7 @@ def enriched_json(self) -> t.Dict: owner_sets.add(frozenset(owners)) wallet_json["all_safe_backup_owners_match"] = len(owner_sets) == 1 - wallet_json["single_safe_backup_owner_per_chain"] = all( + wallet_json["single_backup_owner_per_safe"] = all( len(owner) == 1 for owner in owner_sets ) return wallet_json From ea8381f95824467bbddd29e6f359dbe45f646029 Mon Sep 17 00:00:00 2001 From: jmoreira-valory <jose.moreira.sanchez@valory.xyz> Date: Fri, 22 Nov 2024 18:56:58 +0100 Subject: [PATCH 378/463] chore: add all_chains_same_safe_address --- api.md | 3 ++- operate/wallet/master.py | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/api.md b/api.md index 05b4cb5fe..6a53abf3a 100644 --- a/api.md +++ b/api.md @@ -200,7 +200,7 @@ Returns a list of available wallets ### `GET /api/enriched/wallet` -Returns a list of available wallets with enriched information. It executes on-chain requests to populate the list of owners of each safe, and provides the attributes `all_safe_backup_owners_match` and `single_backup_owner_per_safe`. +Returns a list of available wallets with enriched information. It executes on-chain requests to populate the list of owners of each safe, and provides the attributes `all_chains_same_safe_address`, `all_safe_backup_owners_match` and `single_backup_owner_per_safe`. <details> <summary>Response</summary> @@ -209,6 +209,7 @@ Returns a list of available wallets with enriched information. It executes on-ch [ { "address":"0xFafd5cb31a611C5e5aa65ea8c6226EB4328175E7", + "all_chains_same_safe_address":true, "all_safe_backup_owners_match":false, "ledger_type":"ethereum", "safe_chains":[ diff --git a/operate/wallet/master.py b/operate/wallet/master.py index f7c058e1c..649765b65 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -418,6 +418,7 @@ def enriched_json(self) -> t.Dict: } owner_sets.add(frozenset(owners)) + wallet_json["all_chains_same_safe_address"] = len(set(self.safes.values())) == 1 wallet_json["all_safe_backup_owners_match"] = len(owner_sets) == 1 wallet_json["single_backup_owner_per_safe"] = all( len(owner) == 1 for owner in owner_sets From 741787deb27613ee4c2760b17c55c0b6432d1f9a Mon Sep 17 00:00:00 2001 From: jmoreira-valory <jose.moreira.sanchez@valory.xyz> Date: Fri, 22 Nov 2024 19:25:36 +0100 Subject: [PATCH 379/463] chore: update --- api.md | 11 ++++++++--- operate/wallet/master.py | 8 ++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/api.md b/api.md index 6a53abf3a..d404e58ea 100644 --- a/api.md +++ b/api.md @@ -200,7 +200,11 @@ Returns a list of available wallets ### `GET /api/enriched/wallet` -Returns a list of available wallets with enriched information. It executes on-chain requests to populate the list of owners of each safe, and provides the attributes `all_chains_same_safe_address`, `all_safe_backup_owners_match` and `single_backup_owner_per_safe`. +Returns a list of available wallets with enriched information. It executes on-chain requests to populate the list of owners of each safe, and provides the attributes + +- `consistent_backup_owner`: This flag is `true` when all safes across the chains have exactly the same set of backup owner addresses. It ensures that ownership is identical across all safes, regardless of the number of owners. +- `consistent_backup_owner_count`: This flag is `true` when all safes have the same number of owners, and that number is either 0 (no owners) or 1 (exactly one owner). It checks for uniformity in the count of owners and restricts the count to these two cases. +- `consistent_safe_address`: This flag is `true` when all chains have the same safe address. It ensures there is a single safe address consistently used across all chains. <details> <summary>Response</summary> @@ -209,8 +213,9 @@ Returns a list of available wallets with enriched information. It executes on-ch [ { "address":"0xFafd5cb31a611C5e5aa65ea8c6226EB4328175E7", - "all_chains_same_safe_address":true, - "all_safe_backup_owners_match":false, + "consistent_backup_owner": false, + "consistent_backup_owner_count": false, + "consistent_safe_address": true, "ledger_type":"ethereum", "safe_chains":[ "gnosis", diff --git a/operate/wallet/master.py b/operate/wallet/master.py index 649765b65..0dded776c 100644 --- a/operate/wallet/master.py +++ b/operate/wallet/master.py @@ -418,11 +418,11 @@ def enriched_json(self) -> t.Dict: } owner_sets.add(frozenset(owners)) - wallet_json["all_chains_same_safe_address"] = len(set(self.safes.values())) == 1 - wallet_json["all_safe_backup_owners_match"] = len(owner_sets) == 1 - wallet_json["single_backup_owner_per_safe"] = all( + wallet_json["consistent_safe_address"] = len(set(self.safes.values())) == 1 + wallet_json["consistent_backup_owner"] = len(owner_sets) == 1 + wallet_json["consistent_backup_owner_count"] = all( len(owner) == 1 for owner in owner_sets - ) + ) or all(len(owner) == 0 for owner in owner_sets) return wallet_json @classmethod From 6c3e9d36afb89cbf03d5f2d2945603645ff8b9a1 Mon Sep 17 00:00:00 2001 From: jmoreira-valory <jose.moreira.sanchez@valory.xyz> Date: Fri, 22 Nov 2024 19:26:47 +0100 Subject: [PATCH 380/463] doc: fix doc --- api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api.md b/api.md index d404e58ea..2f9b58569 100644 --- a/api.md +++ b/api.md @@ -203,7 +203,7 @@ Returns a list of available wallets Returns a list of available wallets with enriched information. It executes on-chain requests to populate the list of owners of each safe, and provides the attributes - `consistent_backup_owner`: This flag is `true` when all safes across the chains have exactly the same set of backup owner addresses. It ensures that ownership is identical across all safes, regardless of the number of owners. -- `consistent_backup_owner_count`: This flag is `true` when all safes have the same number of owners, and that number is either 0 (no owners) or 1 (exactly one owner). It checks for uniformity in the count of owners and restricts the count to these two cases. +- `consistent_backup_owner_count`: This flag is `true` when all safes have the same number of owners, and that number is either 0 (no backup owners) or 1 (exactly one backup owner). It checks for uniformity in the count of owners and restricts the count to these two cases. - `consistent_safe_address`: This flag is `true` when all chains have the same safe address. It ensures there is a single safe address consistently used across all chains. <details> From 11c5ea43e3ff66f276417b57e898073ea69edb5e Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Sat, 23 Nov 2024 21:44:09 +0000 Subject: [PATCH 381/463] fix: resolve all build errors --- frontend/.eslintrc.json | 38 +- frontend/client/enums.ts | 14 +- frontend/client/types.ts | 3 +- frontend/components/AddressLink.tsx | 4 +- .../MainPage/MainHeader/FirstRunModal.tsx | 12 +- .../header/AgentButton/AgentButton.tsx | 2 +- .../AgentButton/AgentNotRunningButton.tsx | 41 +- .../header/AgentButton/AgentRunningButton.tsx | 2 +- .../MainPage/header/LastTransaction.tsx | 18 +- frontend/components/MainPage/header/index.tsx | 11 +- .../MainPage/modals/FirstRunModal.tsx | 2 +- .../MainPage/sections/AddFundsSection.tsx | 8 +- .../AlertSections/AddBackupWalletAlert.tsx | 13 +- .../MainPage/sections/GasBalanceSection.tsx | 10 +- .../sections/KeepAgentRunningSection.tsx | 6 +- .../MainPage/sections/NeedsFundsSection.tsx | 2 +- .../MainPage/sections/OlasBalanceSection.tsx | 10 +- .../StakingRewardsThisEpoch.tsx | 2 +- .../CantMigrateAlert.tsx | 33 +- .../StakingContractSection/MigrateButton.tsx | 8 +- .../StakingContractSection/index.tsx | 11 +- .../StakingContractSection/useMigrate.tsx | 10 +- .../components/ManageStakingPage/index.tsx | 4 +- .../AddBackupWalletViaSafePage/index.tsx | 16 +- .../RewardsHistory/RewardsHistory.tsx | 32 +- .../SettingsPage/AddBackupWalletPage.tsx | 34 +- .../SettingsPage/DebugInfoSection.tsx | 96 +- frontend/components/SettingsPage/index.tsx | 4 +- .../SetupPage/Create/SetupEoaFunding.tsx | 12 +- .../components/SetupPage/SetupWelcome.tsx | 5 +- frontend/components/YourWalletPage/Titles.tsx | 2 +- .../components/YourWalletPage/YourAgent.tsx | 16 +- frontend/components/YourWalletPage/index.tsx | 19 +- frontend/config/activityCheckers.ts | 6 +- frontend/config/agents.ts | 12 +- frontend/config/chains.ts | 18 +- frontend/config/mechs.ts | 4 +- frontend/config/olasContracts.ts | 6 +- frontend/config/stakingPrograms/gnosis.ts | 44 +- frontend/config/stakingPrograms/index.ts | 16 +- frontend/config/stakingPrograms/optimism.ts | 46 +- frontend/config/tokens.ts | 20 +- frontend/constants/react-query-keys.ts | 2 +- frontend/constants/serviceTemplates.ts | 8 +- frontend/constants/thresholds.ts | 26 +- frontend/constants/urls.ts | 39 +- frontend/context/BalanceProvider.tsx | 158 +- frontend/context/MasterWalletProvider.tsx | 4 +- frontend/context/RewardProvider.tsx | 9 +- frontend/context/ServicesProvider.tsx | 79 +- .../StakingContractDetailsProvider.tsx | 51 +- frontend/context/StakingProgramProvider.tsx | 39 +- frontend/enums/Chain.ts | 12 +- frontend/enums/Wallet.ts | 12 +- frontend/hooks/useBalanceContext.ts | 37 +- frontend/hooks/useLogs.ts | 37 +- frontend/hooks/useMultisig.ts | 75 +- frontend/hooks/useNeedsFunds.ts | 2 +- frontend/hooks/useNotifyOnNewEpoch.ts | 4 +- frontend/hooks/useRewardsHistory.ts | 24 +- frontend/hooks/useService.ts | 49 +- frontend/hooks/useStakingProgram.ts | 3 +- frontend/package.json | 6 +- frontend/service/Ethers.ts | 12 +- frontend/service/Multicall.ts | 6 +- frontend/service/Services.ts | 20 +- frontend/service/Wallet.ts | 6 +- frontend/service/agents/PredictTrader.ts | 22 +- frontend/service/agents/StakedAgentService.ts | 16 +- frontend/tsconfig.json | 1 + frontend/types/Agent.ts | 10 +- frontend/utils/middlewareHelpers.ts | 24 +- frontend/utils/setupMulticall.ts | 14 +- frontend/yarn.lock | 1703 ++++++++--------- package.json | 9 +- yarn.lock | 5 + 76 files changed, 1614 insertions(+), 1582 deletions(-) diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index 46cd97cea..cf4afb727 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -18,23 +18,43 @@ "import" ], "rules": { + "@next/next/no-html-link-for-pages": "off", // stop Next.js from complaining about pages not being in root + "object-shorthand": [ + "error", + "always" + ], // don't do things like {service: service}, instead just {service} "import/first": "error", "import/newline-after-import": "error", "import/no-duplicates": "error", "simple-import-sort/imports": "error", "simple-import-sort/exports": "error", "unused-imports/no-unused-imports": "error", - "no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], - "no-console": ["error", { "allow": ["error"] }], - "prettier/prettier": ["error", { - "endOfLine": "auto", - "semi": true, - "singleQuote": true - }], + "no-unused-vars": [ + "warn", + { + "argsIgnorePattern": "^_" + } + ], + "no-console": [ + "error", + { + "allow": [ + "error" + ] + } + ], + "prettier/prettier": [ + "error", + { + "endOfLine": "auto", + "semi": true, + "singleQuote": true + } + ], "react/jsx-props-no-spreading": "off", "react/no-array-index-key": "off", - "react/react-in-jsx-scope": "off", - "react-hooks/rules-of-hooks": "error", + "react/react-in-jsx-scope": "off", + "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn" } } \ No newline at end of file diff --git a/frontend/client/enums.ts b/frontend/client/enums.ts index 7a129dac2..22e716848 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -6,13 +6,13 @@ export enum MiddlewareAction { } export enum MiddlewareChain { - ETHEREUM = "ethereum", - GOERLI = "goerli", - GNOSIS = "gnosis", - SOLANA = "solana", - OPTIMISM = "optimism", - BASE = "base", - MODE = "mode", + ETHEREUM = 'ethereum', + GOERLI = 'goerli', + GNOSIS = 'gnosis', + SOLANA = 'solana', + OPTIMISM = 'optimism', + BASE = 'base', + MODE = 'mode', } export enum MiddlewareLedger { diff --git a/frontend/client/types.ts b/frontend/client/types.ts index dfa294931..0876b80bb 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -10,6 +10,7 @@ import { } from './enums'; export type ServiceHash = string; +export type ServiceConfigId = string; export type ServiceKeys = { address: Address; @@ -55,7 +56,7 @@ export type MiddlewareServiceResponse = { service_path?: string; version: string; chain_configs: { - [chain in MiddlewareChain]: { + [middlewareChain in MiddlewareChain]: { ledger_config: LedgerConfig; chain_data: ChainData; }; diff --git a/frontend/components/AddressLink.tsx b/frontend/components/AddressLink.tsx index 2f7398b4b..21273573c 100644 --- a/frontend/components/AddressLink.tsx +++ b/frontend/components/AddressLink.tsx @@ -1,6 +1,6 @@ import { MiddlewareChain } from '@/client'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { EXPLORER_URL } from '@/constants/urls'; +import { EXPLORER_URL_BY_MIDDLEWARE_CHAIN } from '@/constants/urls'; import { Address } from '@/types/Address'; import { truncateAddress } from '@/utils/truncate'; @@ -15,7 +15,7 @@ export const AddressLink = ({ return ( <a target="_blank" - href={`${EXPLORER_URL[MiddlewareChain.OPTIMISM]}/address/${address}`} + href={`${EXPLORER_URL_BY_MIDDLEWARE_CHAIN[MiddlewareChain.OPTIMISM]}/address/${address}`} > {truncateAddress(address)} diff --git a/frontend/components/MainPage/MainHeader/FirstRunModal.tsx b/frontend/components/MainPage/MainHeader/FirstRunModal.tsx index 6ad833b97..f52543f53 100644 --- a/frontend/components/MainPage/MainHeader/FirstRunModal.tsx +++ b/frontend/components/MainPage/MainHeader/FirstRunModal.tsx @@ -3,18 +3,16 @@ import Image from 'next/image'; import { FC } from 'react'; import { MODAL_WIDTH } from '@/constants/width'; -import { useServiceTemplates } from '@/hooks/useServiceTemplates'; +import { TokenSymbol } from '@/enums/Token'; +import { useStakingProgram } from '@/hooks/useStakingProgram'; type FirstRunModalProps = { open: boolean; onClose: () => void }; export const FirstRunModal: FC<FirstRunModalProps> = ({ open, onClose }) => { - const { getServiceTemplates } = useServiceTemplates(); + const { activeStakingProgramMeta } = useStakingProgram(); - if (!open) return null; - - const minimumStakedAmountRequired = getMinimumStakedAmountRequired( - getServiceTemplates()[0], - ); + const minimumStakedAmountRequired = + activeStakingProgramMeta?.stakingRequirements?.[TokenSymbol.OLAS]; return ( <Modal diff --git a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx index ba1f8180f..f3ef165f6 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx @@ -27,7 +27,7 @@ export const AgentButton = () => { service, deploymentStatus: serviceStatus, isLoaded, - } = useService({ serviceConfigId }); + } = useService(serviceConfigId); assertRequired( // TODO: review whether this causes agent button to not render diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index fbe8aaf3c..9e5303012 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -24,48 +24,55 @@ import { useMasterWalletContext } from '@/hooks/useWallet'; import { ServicesService } from '@/service/Services'; import { WalletService } from '@/service/Wallet'; import { delayInSeconds } from '@/utils/delay'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; /** Button used to start / deploy the agent */ export const AgentNotRunningButton = () => { - const { masterWallets: wallets } = useMasterWalletContext(); + const { storeState } = useStore(); + const { showNotification } = useElectronApi(); + + const { masterWallets } = useMasterWalletContext(); const { selectedService, setPaused: setIsServicePollingPaused, - isFetched: isLoaded, refetch: updateServicesState, } = useServices(); - const { service, deploymentStatus, setDeploymentStatus } = useService({ - serviceConfigId: - isLoaded && selectedService ? selectedService?.service_config_id : '', - }); - const { showNotification } = useElectronApi(); + + const { service, deploymentStatus, setDeploymentStatus } = useService( + selectedService?.service_config_id, + ); + const { setIsPaused: setIsBalancePollingPaused, totalStakedOlasBalance, totalEthBalance, updateBalances, } = useBalanceContext(); - const { serviceSafeBalances, isLowBalance } = useServiceBalances( + + const { serviceSafeBalances } = useServiceBalances( selectedService?.service_config_id, ); - const { storeState } = useStore(); + const { isAllStakingContractDetailsRecordLoaded, setIsPaused: setIsStakingContractInfoPollingPaused, refetchActiveStakingContractDetails, } = useStakingContractContext(); + const { activeStakingProgramId } = useStakingProgram(); + const { isEligibleForStaking, isAgentEvicted, isServiceStaked } = useActiveStakingContractInfo(); + const { hasEnoughServiceSlots } = useActiveStakingContractInfo(); const requiredStakedOlas = service && activeStakingProgramId && - STAKING_PROGRAMS[service.home_chain_id][activeStakingProgramId] + STAKING_PROGRAMS[asEvmChainId(service.home_chain)][activeStakingProgramId] ?.stakingRequirements[TokenSymbol.OLAS]; - const safeOlasBalance = serviceSafeBalances.find( + const safeOlasBalance = serviceSafeBalances?.find( (walletBalanceResult) => walletBalanceResult.symbol === TokenSymbol.OLAS, )?.balance; @@ -95,7 +102,7 @@ export const AgentNotRunningButton = () => { ]); const createSafeIfNeeded = useCallback(async () => { - if (!service?.chain_configs[service.home_chain_id]?.chain_data?.multisig) { + if (!service?.chain_configs[service.home_chain]?.chain_data?.multisig) { await WalletService.createSafe(MiddlewareChain.OPTIMISM); } }, [service]); @@ -108,7 +115,7 @@ export const AgentNotRunningButton = () => { serviceTemplate: SERVICE_TEMPLATES[0], // TODO: support multi-agent, during optimus week deploy: true, useMechMarketplace: - STAKING_PROGRAMS[+SERVICE_TEMPLATES[0].home_chain_id][ // TODO: support multi-agent, during optimus week + STAKING_PROGRAMS[asEvmChainId(SERVICE_TEMPLATES[0].home_chain)][ // TODO: support multi-agent, during optimus week activeStakingProgramId ].mechType === MechType.Marketplace, }); @@ -129,7 +136,7 @@ export const AgentNotRunningButton = () => { ]); const handleStart = useCallback(async () => { - if (!wallets?.[0]) return; + if (!masterWallets?.[0]) return; pauseAllPolling(); setDeploymentStatus(MiddlewareDeploymentStatus.DEPLOYING); @@ -149,7 +156,7 @@ export const AgentNotRunningButton = () => { resumeAllPolling(); } }, [ - wallets, + masterWallets, pauseAllPolling, resumeAllPolling, setDeploymentStatus, @@ -165,7 +172,8 @@ export const AgentNotRunningButton = () => { const isServiceInactive = deploymentStatus === MiddlewareDeploymentStatus.BUILT || deploymentStatus === MiddlewareDeploymentStatus.STOPPED; - if (isServiceInactive && isLowBalance) return false; + + if (isServiceInactive) return false; // TOOD: check if master safe is low balance relative to service's active staking program id if ( [ @@ -192,7 +200,6 @@ export const AgentNotRunningButton = () => { }, [ isAllStakingContractDetailsRecordLoaded, deploymentStatus, - isLowBalance, requiredStakedOlas, hasEnoughServiceSlots, isServiceStaked, diff --git a/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx index 3b5626b36..6dc160422 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentRunningButton.tsx @@ -38,7 +38,7 @@ export const AgentRunningButton = () => { isLoaded && selectedService?.service_config_id ? selectedService.service_config_id : ''; - const { service, setDeploymentStatus } = useService({ serviceConfigId }); + const { service, setDeploymentStatus } = useService(serviceConfigId); const handlePause = useCallback(async () => { if (!service) return; diff --git a/frontend/components/MainPage/header/LastTransaction.tsx b/frontend/components/MainPage/header/LastTransaction.tsx index 069a9a58d..23373cd42 100644 --- a/frontend/components/MainPage/header/LastTransaction.tsx +++ b/frontend/components/MainPage/header/LastTransaction.tsx @@ -5,11 +5,10 @@ import { useInterval } from 'usehooks-ts'; import { MiddlewareChain } from '@/client'; import { ONE_MINUTE_INTERVAL } from '@/constants/intervals'; -import { EXPLORER_URL } from '@/constants/urls'; +import { EXPLORER_URL_BY_MIDDLEWARE_CHAIN } from '@/constants/urls'; import { usePageState } from '@/hooks/usePageState'; import { useService } from '@/hooks/useService'; import { useStakingProgram } from '@/hooks/useStakingProgram'; -import { useMasterWalletContext } from '@/hooks/useWallet'; import { getLatestTransaction } from '@/service/Ethers'; import { TransactionInfo } from '@/types/TransactionInfo'; import { Optional } from '@/types/Util'; @@ -35,25 +34,26 @@ type LastTransactionProps = { serviceConfigId: Optional<string> }; export const LastTransaction = ({ serviceConfigId }: LastTransactionProps) => { const { isPageLoadedAndOneMinutePassed } = usePageState(); const { activeStakingProgramMeta } = useStakingProgram(); - const { service } = useService({ serviceConfigId }); - const { masterSafes } = useMasterWalletContext(); - const multisigAddress = masterSafe; + const { serviceSafes } = useService(serviceConfigId); + + const serviceSafe = serviceSafes?.[0]; + const chainId = activeStakingProgramMeta?.chainId; const [isFetching, setIsFetching] = useState(true); const [transaction, setTransaction] = useState<TransactionInfo | null>(null); const fetchTransaction = useCallback(async () => { - if (!multisigAddress) return; + if (!serviceSafe?.address) return; if (!chainId) return; - getLatestTransaction(multisigAddress, chainId) + getLatestTransaction(serviceSafe.address, chainId) .then((tx) => setTransaction(tx)) .catch((error) => console.error('Failed to get latest transaction', error), ) .finally(() => setIsFetching(false)); - }, [multisigAddress, chainId]); + }, [serviceSafe, chainId]); // Poll for the latest transaction useInterval(() => fetchTransaction(), ONE_MINUTE_INTERVAL); @@ -86,7 +86,7 @@ export const LastTransaction = ({ serviceConfigId }: LastTransactionProps) => { className="text-xs pointer hover-underline" onClick={() => window.open( - `${EXPLORER_URL[MiddlewareChain.OPTIMISM]}/tx/${transaction.hash}`, + `${EXPLORER_URL_BY_MIDDLEWARE_CHAIN[MiddlewareChain.OPTIMISM]}/tx/${transaction.hash}`, ) } > diff --git a/frontend/components/MainPage/header/index.tsx b/frontend/components/MainPage/header/index.tsx index 036af9f57..c325b83f6 100644 --- a/frontend/components/MainPage/header/index.tsx +++ b/frontend/components/MainPage/header/index.tsx @@ -15,9 +15,7 @@ import { AgentHead } from './AgentHead'; const useSetupTrayIcon = () => { const { isLowBalance } = useBalanceContext(); const { selectedService } = useServices(); - const { deploymentStatus } = useService({ - serviceConfigId: selectedService?.service_config_id, - }); + const { deploymentStatus } = useService(selectedService?.service_config_id); const { setTrayIcon } = useElectronApi(); useEffect(() => { @@ -40,10 +38,9 @@ export const MainHeader = () => { const handleModalClose = useCallback(() => setIsFirstRunModalOpen(false), []); const { selectedService } = useServices(); - const configId = selectedService?.service_config_id; - const { isLoaded: isServiceLoaded } = useService({ - serviceConfigId: configId, - }); + const { isLoaded: isServiceLoaded } = useService( + selectedService?.service_config_id, + ); const { isActiveStakingProgramLoaded } = useStakingProgram(); useSetupTrayIcon(); diff --git a/frontend/components/MainPage/modals/FirstRunModal.tsx b/frontend/components/MainPage/modals/FirstRunModal.tsx index 95e3d57f5..611ecdb14 100644 --- a/frontend/components/MainPage/modals/FirstRunModal.tsx +++ b/frontend/components/MainPage/modals/FirstRunModal.tsx @@ -14,7 +14,7 @@ type FirstRunModalProps = { open: boolean; onClose: () => void }; export const FirstRunModal: FC<FirstRunModalProps> = ({ open, onClose }) => { const { selectedAgentConfig } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; const { activeStakingProgramId } = useStakingProgram(); if (!open) return null; diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index 37f3f189a..ba7dfb8df 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -76,11 +76,11 @@ export const AddFundsSection = () => { export const OpenAddFundsSection = forwardRef<HTMLDivElement>((_, ref) => { const { selectedAgentConfig } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; const { masterSafes } = useMasterWalletContext(); const masterSafeAddress = useMemo( () => - masterSafes?.find((wallet) => wallet.chainId === homeChainId)?.address, + masterSafes?.find((wallet) => wallet.evmChainId === homeChainId)?.address, [homeChainId, masterSafes], ); @@ -114,7 +114,7 @@ OpenAddFundsSection.displayName = 'OpenAddFundsSection'; const AddFundsWarningAlertSection = () => { const { selectedAgentConfig } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; return ( <CardSection> <CustomAlert @@ -174,7 +174,7 @@ const AddFundsAddressSection = ({ const AddFundsGetTokensSection = () => { const { selectedAgentConfig } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; return ( <CardSection justify="center" bordertop="true" padding="16px 24px"> diff --git a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx index 2428d3f12..ed8def1fe 100644 --- a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx +++ b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx @@ -2,17 +2,22 @@ import { Flex, Typography } from 'antd'; import { isArray } from 'lodash'; import { Pages } from '@/enums/Pages'; -import { MasterSafe } from '@/enums/Wallet'; -import { useMultisig } from '@/hooks/useMultisig'; +import { useMultisigs } from '@/hooks/useMultisig'; import { usePageState } from '@/hooks/usePageState'; +import { useMasterWalletContext } from '@/hooks/useWallet'; import { CustomAlert } from '../../../Alert'; const { Text } = Typography; -export const AddBackupWalletAlert = (masterSafe: MasterSafe) => { +export const AddBackupWalletAlert = () => { const { goto } = usePageState(); - const { owners, ownersIsPending, ownersIsFetched } = useMultisig(masterSafe); + const { masterSafes } = useMasterWalletContext(); + const { + masterSafesOwners: owners, + masterSafesOwnersIsPending: ownersIsPending, + masterSafesOwnersIsFetched: ownersIsFetched, + } = useMultisigs(masterSafes); if (ownersIsPending) return null; if (!ownersIsFetched) return null; diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index 435945fcb..55fef650e 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -5,7 +5,7 @@ import { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; -import { EXPLORER_URL } from '@/constants/urls'; +import { EXPLORER_URL_BY_MIDDLEWARE_CHAIN } from '@/constants/urls'; import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; @@ -98,14 +98,14 @@ const TooltipContent = styled.div` export const GasBalanceSection = () => { const { selectedAgentConfig } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; const { masterSafes } = useMasterWalletContext(); const { isLoaded: isBalancesLoaded } = useBalanceContext(); const masterSafe = useMemo(() => { if (isNil(masterSafes)) return; - return masterSafes.find((wallet) => wallet.chainId === homeChainId); + return masterSafes.find((wallet) => wallet.evmChainId === homeChainId); }, [homeChainId, masterSafes]); return ( @@ -126,9 +126,9 @@ export const GasBalanceSection = () => { <a href={ `${ - EXPLORER_URL[ + EXPLORER_URL_BY_MIDDLEWARE_CHAIN[ // TODO: fix unknown - homeChainId as unknown as keyof typeof EXPLORER_URL + homeChainId as unknown as keyof typeof EXPLORER_URL_BY_MIDDLEWARE_CHAIN ] }/address/` + masterSafe.address } diff --git a/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx b/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx index fdd8e8a0a..39c7ac30b 100644 --- a/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx +++ b/frontend/components/MainPage/sections/KeepAgentRunningSection.tsx @@ -16,9 +16,9 @@ export const KeepAgentRunningSection = () => { const { storeState } = useStore(); const { selectedService } = useServices(); - const { deploymentStatus: serviceStatus } = useService({ - serviceConfigId: selectedService?.service_config_id, - }); + const { deploymentStatus: serviceStatus } = useService( + selectedService?.service_config_id, + ); if (storeState?.firstStakingRewardAchieved) return null; if (serviceStatus !== MiddlewareDeploymentStatus.DEPLOYED) return null; diff --git a/frontend/components/MainPage/sections/NeedsFundsSection.tsx b/frontend/components/MainPage/sections/NeedsFundsSection.tsx index cb5abf400..d87c19082 100644 --- a/frontend/components/MainPage/sections/NeedsFundsSection.tsx +++ b/frontend/components/MainPage/sections/NeedsFundsSection.tsx @@ -30,7 +30,7 @@ export const MainNeedsFunds = () => { } = useNeedsFunds(); const { selectedAgentConfig } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; const electronApi = useElectronApi(); diff --git a/frontend/components/MainPage/sections/OlasBalanceSection.tsx b/frontend/components/MainPage/sections/OlasBalanceSection.tsx index 54558e345..cb034bae9 100644 --- a/frontend/components/MainPage/sections/OlasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/OlasBalanceSection.tsx @@ -1,5 +1,6 @@ import { RightOutlined } from '@ant-design/icons'; import { Flex, Skeleton, Typography } from 'antd'; +import { sum } from 'lodash'; import { useMemo } from 'react'; import styled from 'styled-components'; @@ -67,10 +68,11 @@ export const MainOlasBalance = ({ 0, ); - const totalOlasBalance = - masterWalletOlasBalance + - serviceWalletOlasBalance + - serviceStakedOlasBalance; + const totalOlasBalance = sum([ + masterWalletOlasBalance, + serviceWalletOlasBalance, + serviceStakedOlasBalance, + ]); return balanceFormat(totalOlasBalance, 2); }, [masterWalletBalances, serviceStakedBalances, serviceWalletBalances]); diff --git a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx index 0f25e36b1..e8e9303f6 100644 --- a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx @@ -14,7 +14,7 @@ const { Text } = Typography; const useEpochEndTime = () => { const { selectedAgentConfig } = useServices(); - const chainId = selectedAgentConfig.homeChainId; + const chainId = selectedAgentConfig.evmHomeChainId; const { activeStakingProgramAddress } = useStakingProgram(); diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx index e069dd485..62977ed07 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx @@ -5,7 +5,6 @@ import { useMemo } from 'react'; import { CustomAlert } from '@/components/Alert'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { LOW_MASTER_SAFE_BALANCE } from '@/constants/thresholds'; -import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { @@ -13,7 +12,6 @@ import { useMasterBalances, } from '@/hooks/useBalanceContext'; import { useNeedsFunds } from '@/hooks/useNeedsFunds'; -import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useActiveStakingContractInfo, @@ -29,19 +27,7 @@ type CantMigrateAlertProps = { stakingProgramId: StakingProgramId }; const AlertInsufficientMigrationFunds = ({ stakingProgramId: stakingProgramIdToMigrateTo, }: CantMigrateAlertProps) => { - const { - isFetched: isServicesLoaded, - selectedService, - selectedAgentConfig, - } = useServices(); - const { homeChainId } = selectedAgentConfig; - const serviceConfigId = - isServicesLoaded && selectedService - ? selectedService.service_config_id - : ''; - const { service } = useService({ - serviceConfigId, - }); + const { selectedAgentConfig } = useServices(); const { isAllStakingContractDetailsRecordLoaded } = useStakingContractContext(); const { isServiceStaked } = useActiveStakingContractInfo(); @@ -50,26 +36,24 @@ const AlertInsufficientMigrationFunds = ({ const { masterSafeBalances } = useMasterBalances(); const { serviceFundRequirements, isInitialFunded } = useNeedsFunds(); - // should find in STAKING_PROGRAMS based on stakingProgramIdToMigrateTo? - const chainIdToMigrateTo = ChainId.Gnosis; - const requiredStakedOlas = - STAKING_PROGRAMS[chainIdToMigrateTo][stakingProgramIdToMigrateTo] - ?.stakingRequirements[TokenSymbol.OLAS]; + STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][ + stakingProgramIdToMigrateTo + ]?.stakingRequirements[TokenSymbol.OLAS]; const safeBalance = useMemo(() => { if (!isBalanceLoaded) return; if (isNil(masterSafeBalances) || isEmpty(masterSafeBalances)) return; masterSafeBalances.reduce( (acc, { chainId, symbol, balance }) => { - if (chainId === homeChainId) { + if (chainId === selectedAgentConfig.evmHomeChainId) { acc[symbol] = balance; } return acc; }, {} as Record<TokenSymbol, number>, ); - }, [homeChainId, isBalanceLoaded, masterSafeBalances]); + }, [isBalanceLoaded, masterSafeBalances, selectedAgentConfig.evmHomeChainId]); if (!isAllStakingContractDetailsRecordLoaded) return null; if (isNil(requiredStakedOlas)) return null; @@ -83,8 +67,9 @@ const AlertInsufficientMigrationFunds = ({ const requiredXdaiDeposit = isInitialFunded ? LOW_MASTER_SAFE_BALANCE - (safeBalance[TokenSymbol.ETH] || 0) // is already funded allow minimal maintenance - : (serviceFundRequirements[homeChainId]?.[TokenSymbol.ETH] || 0) - - (safeBalance[TokenSymbol.ETH] || 0); // otherwise require full initial funding requirements + : (serviceFundRequirements[selectedAgentConfig.evmHomeChainId]?.[ + TokenSymbol.ETH + ] || 0) - (safeBalance[TokenSymbol.ETH] || 0); // otherwise require full initial funding requirements return ( <CustomAlert diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index 9bcf3063d..82948d398 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -34,14 +34,12 @@ export const MigrateButton = ({ selectedService, selectedAgentConfig, } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; const serviceConfigId = isServicesLoaded && selectedService ? selectedService.service_config_id : ''; - const { service, setDeploymentStatus } = useService({ - serviceConfigId, - }); + const { service, setDeploymentStatus } = useService(serviceConfigId); const serviceTemplate = useMemo<ServiceTemplate | undefined>( () => (service ? getServiceTemplate(service.hash) : undefined), [service], @@ -122,7 +120,7 @@ export const MigrateButton = ({ await ServicesService.updateService({ stakingProgramId: stakingProgramIdToMigrateTo, serviceTemplate, - serviceUuid: serviceConfigId, + serviceConfigId, deploy: true, useMechMarketplace: stakingProgramIdToMigrateTo === diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 51206d27f..9a17bbd83 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -3,12 +3,12 @@ import { useMemo } from 'react'; import { CardSection } from '@/components/styled/CardSection'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { EXPLORER_URL } from '@/constants/urls'; +import { EXPLORER_URL_BY_EVM_CHAIN_ID } from '@/constants/urls'; import { StakingProgramId } from '@/enums/StakingProgram'; import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; import { useServices } from '@/hooks/useServices'; import { useStakingProgram } from '@/hooks/useStakingProgram'; -import { Maybe } from '@/types/Util'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; import { CantMigrateAlert } from './CantMigrateAlert'; import { MigrateButton } from './MigrateButton'; @@ -86,8 +86,7 @@ export const StakingContractSection = ({ ); }, [migrateValidation]); - const chainId: Maybe<keyof typeof EXPLORER_URL> = - selectedService?.home_chain_id; + const evmChainId = asEvmChainId(selectedService?.home_chain); return ( <> @@ -109,9 +108,9 @@ export const StakingContractSection = ({ <StakingContractDetails stakingProgramId={stakingProgramId} /> - {chainId && ( + {evmChainId && ( <a - href={`${EXPLORER_URL[chainId]}/address/${activeStakingProgramAddress}`} + href={`${EXPLORER_URL_BY_EVM_CHAIN_ID[evmChainId]}/address/${activeStakingProgramAddress}`} target="_blank" > View contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index 64d16aef6..d3aecf1f5 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -50,11 +50,9 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { selectedService, selectedAgentType, } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; const serviceConfigId = selectedService?.service_config_id; - const { deploymentStatus: serviceStatus } = useService({ - serviceConfigId, - }); + const { deploymentStatus: serviceStatus } = useService(serviceConfigId); const { isLoaded: isBalanceLoaded, @@ -87,9 +85,9 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { const minimumOlasRequiredToMigrate = useMemo( () => - STAKING_PROGRAMS[selectedAgentConfig.homeChainId][stakingProgramId] + STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][stakingProgramId] .stakingRequirements[TokenSymbol.OLAS], - [selectedAgentConfig.homeChainId, stakingProgramId], + [selectedAgentConfig.evmHomeChainId, stakingProgramId], ); const hasEnoughOlasToMigrate = useMemo(() => { if (!isBalanceLoaded) return false; diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index d46cd19c1..dd009f48e 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -31,7 +31,7 @@ export const ManageStakingPage = () => { // if the program is deprecated, ignore it if ( - STAKING_PROGRAMS[selectedAgentConfig.homeChainId][stakingProgramId] + STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][stakingProgramId] .deprecated ) { return acc; @@ -44,7 +44,7 @@ export const ManageStakingPage = () => { const otherStakingProgramIds = orderedStakingProgramIds.filter( (stakingProgramId) => { const info = - STAKING_PROGRAMS[selectedAgentConfig.homeChainId][stakingProgramId]; + STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][stakingProgramId]; if (!info) return false; if (activeStakingProgramId === stakingProgramId) return false; if (info.deprecated) return false; diff --git a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx index a06d5b62c..8cafd2a89 100644 --- a/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx +++ b/frontend/components/Pages/AddBackupWalletViaSafePage/index.tsx @@ -4,7 +4,7 @@ import { isNil } from 'lodash'; import { CardTitle } from '@/components/Card/CardTitle'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { DISCORD_TICKET_URL } from '@/constants/urls'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { useServices } from '@/hooks/useServices'; import { useMasterWalletContext } from '@/hooks/useWallet'; @@ -16,24 +16,24 @@ const { Text } = Typography; * update as needed; check https://app.safe.global/new-safe/create for prefixes */ const safeChainPrefix = { - [ChainId.Ethereum]: 'eth', - [ChainId.Base]: 'base', - [ChainId.Optimism]: 'oeth', - [ChainId.Gnosis]: 'gno', + [EvmChainId.Ethereum]: 'eth', + [EvmChainId.Base]: 'base', + [EvmChainId.Optimism]: 'oeth', + [EvmChainId.Gnosis]: 'gno', }; export const AddBackupWalletViaSafePage = () => { const { - selectedAgentConfig: { homeChainId }, + selectedAgentConfig: { evmHomeChainId: homeChainId }, } = useServices(); const { masterSafes } = useMasterWalletContext(); const masterSafe = masterSafes?.find( - ({ chainId }) => homeChainId === chainId, + ({ evmChainId: chainId }) => homeChainId === chainId, ); const safePrefix = - masterSafe?.chainId && safeChainPrefix[masterSafe?.chainId]; + masterSafe?.evmChainId && safeChainPrefix[masterSafe?.evmChainId]; if (isNil(masterSafe)) { return null; diff --git a/frontend/components/RewardsHistory/RewardsHistory.tsx b/frontend/components/RewardsHistory/RewardsHistory.tsx index 2e294f11b..0783050fd 100644 --- a/frontend/components/RewardsHistory/RewardsHistory.tsx +++ b/frontend/components/RewardsHistory/RewardsHistory.tsx @@ -25,12 +25,13 @@ import { CardFlex } from '@/components/styled/CardFlex'; import { STAKING_PROGRAM_ADDRESS } from '@/config/stakingPrograms'; import { COLOR } from '@/constants/colors'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { EXPLORER_URL } from '@/constants/urls'; +import { EXPLORER_URL_BY_MIDDLEWARE_CHAIN } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; import { StakingProgramId } from '@/enums/StakingProgram'; import { usePageState } from '@/hooks/usePageState'; import { useServices } from '@/hooks/useServices'; import { useStakingProgram } from '@/hooks/useStakingProgram'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; import { balanceFormat } from '@/utils/numberFormatters'; import { formatToMonthDay, formatToShortDateTime } from '@/utils/time'; @@ -129,7 +130,7 @@ const EpochTime = ({ epoch }: { epoch: EpochDetails }) => { {timePeriod} </Text> <a - href={`${EXPLORER_URL[MiddlewareChain.OPTIMISM]}/tx/${epoch.transactionHash}`} + href={`${EXPLORER_URL_BY_MIDDLEWARE_CHAIN[MiddlewareChain.OPTIMISM]}/tx/${epoch.transactionHash}`} target="_blank" > End of epoch transaction {UNICODE_SYMBOLS.EXTERNAL_LINK} @@ -180,16 +181,24 @@ const ContractRewards = ({ checkpoints }: ContractRewardsProps) => { ); }; +/** + * TODO: Refactor, only supports a single service for now + * */ export const RewardsHistory = () => { const { contractCheckpoints, isError, isLoading, isFetching, refetch } = useRewardsHistory(); const { goto } = usePageState(); const { selectedService } = useServices(); - const serviceId = selectedService?.service_config_id; - const chainId = selectedService?.home_chain_id; + + const serviceConfigId = selectedService?.service_config_id; + const serviceNftTokenId = + selectedService?.chain_configs[selectedService?.home_chain]?.chain_data + .token; + + const evmChainId = asEvmChainId(selectedService?.home_chain); const history = useMemo(() => { - if (isLoading || isFetching || !serviceId) return <Loading />; + if (isLoading || isFetching || !serviceConfigId) return <Loading />; if (isError) return <ErrorLoadingHistory refetch={refetch} />; if (!contractCheckpoints) return <NoRewardsHistory />; if (Object.keys(contractCheckpoints).length === 0) { @@ -201,7 +210,7 @@ export const RewardsHistory = () => { .flat() .sort((a, b) => b.epochEndTimeStamp - a.epochEndTimeStamp) .find((checkpoint) => - checkpoint.serviceIds.includes(`${serviceId}`), + checkpoint.serviceIds.includes(`${serviceNftTokenId}`), )?.contractAddress; // most recent transaction staking contract at the top of the list @@ -213,14 +222,14 @@ export const RewardsHistory = () => { }, ); - if (!chainId) return null; + if (!evmChainId) return null; return ( <Flex vertical gap={16}> {latestContractAddresses.map((contractAddress: string) => { const checkpoints = contractCheckpoints[contractAddress]; const [stakingProgramId] = Object.entries( - STAKING_PROGRAM_ADDRESS[chainId], + STAKING_PROGRAM_ADDRESS[evmChainId], ).find((entry) => { const [, stakingProxyAddress] = entry; return ( @@ -244,11 +253,12 @@ export const RewardsHistory = () => { }, [ isLoading, isFetching, + serviceConfigId, isError, - serviceId, - chainId, - contractCheckpoints, refetch, + contractCheckpoints, + evmChainId, + serviceNftTokenId, ]); return ( diff --git a/frontend/components/SettingsPage/AddBackupWalletPage.tsx b/frontend/components/SettingsPage/AddBackupWalletPage.tsx index 29271cb59..ac6d33638 100644 --- a/frontend/components/SettingsPage/AddBackupWalletPage.tsx +++ b/frontend/components/SettingsPage/AddBackupWalletPage.tsx @@ -1,29 +1,39 @@ import { CloseOutlined } from '@ant-design/icons'; import { Button, Form, Input, Typography } from 'antd'; +import { isEmpty, isNil } from 'lodash'; import { useMemo } from 'react'; -import { MiddlewareChain } from '@/client'; import { MIN_ETH_BALANCE_THRESHOLDS } from '@/constants/thresholds'; import { SettingsScreen } from '@/enums/SettingsScreen'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { useMasterBalances } from '@/hooks/useBalanceContext'; +import { useServices } from '@/hooks/useServices'; import { useSettings } from '@/hooks/useSettings'; import { CardTitle } from '../Card/CardTitle'; import { CardFlex } from '../styled/CardFlex'; export const AddBackupWalletPage = () => { - const { masterEoaBalance: eoaBalance } = useBalanceContext(); + const { + selectedAgentConfig: { evmHomeChainId: homeChainId }, + } = useServices(); + const { masterEoaBalances } = useMasterBalances(); const { goto } = useSettings(); - const [form] = Form.useForm(); - const isFunded = useMemo<boolean>(() => { - if (!eoaBalance) return false; - return ( - eoaBalance.ETH >= - MIN_ETH_BALANCE_THRESHOLDS[MiddlewareChain.OPTIMISM].safeAddSigner - ); - }, [eoaBalance]); + const isMasterEoaFunded = useMemo<boolean>(() => { + if (isNil(masterEoaBalances) || isEmpty(masterEoaBalances)) return false; + + const masterEoaNativeBalance = masterEoaBalances.find( + ({ isNative, chainId }) => isNative && chainId === homeChainId, + )?.balance; + + if (isNil(masterEoaNativeBalance)) return false; + + const nativeBalanceRequiredToAddSigner = + MIN_ETH_BALANCE_THRESHOLDS[homeChainId].safeAddSigner; + + return masterEoaNativeBalance >= nativeBalanceRequiredToAddSigner; + }, [homeChainId, masterEoaBalances]); return ( <CardFlex @@ -55,7 +65,7 @@ export const AddBackupWalletPage = () => { > <Input placeholder="e.g. 0x123124...124124" size="large" /> </Form.Item> - <Button type="primary" disabled={!isFunded} htmlType="submit"> + <Button type="primary" disabled={!isMasterEoaFunded} htmlType="submit"> Add backup wallet </Button> </Form> diff --git a/frontend/components/SettingsPage/DebugInfoSection.tsx b/frontend/components/SettingsPage/DebugInfoSection.tsx index 83d934247..8f3192b6c 100644 --- a/frontend/components/SettingsPage/DebugInfoSection.tsx +++ b/frontend/components/SettingsPage/DebugInfoSection.tsx @@ -15,10 +15,10 @@ import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { EXPLORER_URL } from '@/constants/urls'; +import { EXPLORER_URL_BY_EVM_CHAIN_ID } from '@/constants/urls'; import { MODAL_WIDTH } from '@/constants/width'; import { WalletBalanceResult } from '@/context/BalanceProvider'; -import { ChainId, ChainName } from '@/enums/Chain'; +import { EvmChainId, EvmChainName } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; import { WalletType } from '@/enums/Wallet'; import { @@ -61,7 +61,7 @@ const DebugItem = ({ }: { item: { title: string; - balance: Record<number | ChainId, Record<string | TokenSymbol, number>>; + balance: Record<number | EvmChainId, Record<string | TokenSymbol, number>>; address: `0x${string}`; link?: { title: string; href: string }; }; @@ -76,7 +76,11 @@ const DebugItem = ({ [item.address], ); - const chainIds = Object.keys(item.balance); + const evmChainIds = useMemo<EvmChainId[]>(() => { + return Object.keys(item.balance).map((chainId: string) => { + return +chainId as EvmChainId; + }); + }, [item.balance]); return ( <Card> @@ -93,7 +97,7 @@ const DebugItem = ({ return ( <Flex key={chainId} vertical gap={4}> <Text type="secondary" className="text-sm"> - {ChainName[+chainId as keyof typeof ChainName]} + {EvmChainName[+chainId as keyof typeof EvmChainName]} </Text> {Object.entries(balance).map(([tokenSymbol, balance]) => { return ( @@ -110,17 +114,16 @@ const DebugItem = ({ </Col> <Col span={12}> - {chainIds.map((chainId) => ( + {evmChainIds.map((chainId) => ( <Flex vertical gap={4} align="flex-start" key={chainId}> <Text type="secondary" className="text-sm"> Address{' '} - {chainIds.length > 1 && - `on ${ChainName[+chainId as keyof typeof ChainName]}`} + {evmChainIds.length > 1 && `on ${EvmChainName[chainId]}`} </Text> <Flex gap={12}> <a target="_blank" - href={`${EXPLORER_URL[+chainId as keyof typeof EXPLORER_URL]}/address/${item.address}`} + href={`${EXPLORER_URL_BY_EVM_CHAIN_ID[chainId]}/address/${item.address}`} > {truncatedAddress} </a> @@ -148,7 +151,7 @@ const DebugItem = ({ export const DebugInfoSection = () => { const { masterEoa, masterSafes } = useMasterWalletContext(); - const { serviceAddresses } = useServices(); + const { serviceWallets: serviceAddresses } = useServices(); const { walletBalances } = useBalanceContext(); const { masterEoaBalances, masterSafeBalances } = useMasterBalances(); @@ -163,46 +166,61 @@ export const DebugInfoSection = () => { const result: { title: string; - balance: Record<number | ChainId, Record<string | TokenSymbol, number>>; + balance: Record< + number | EvmChainId, + Record<string | TokenSymbol, number> + >; address: Address; link?: { title: string; href: string }; }[] = []; - result.push({ - title: 'Master EOA', - ...getBalanceData(masterEoaBalances), - address: masterEoa.address, - }); - - masterSafes.forEach((wallet) => { + if (!isNil(masterEoaBalances)) { result.push({ - title: 'Master Safe', - ...getBalanceData(masterSafeBalances), - address: wallet.address, + title: 'Master EOA', + ...getBalanceData(masterEoaBalances), + address: masterEoa.address, }); - }); + } - serviceAddresses?.forEach((wallet) => { - if (wallet.type === WalletType.EOA) { + if (!isNil(masterSafeBalances)) { + masterSafes.forEach((wallet) => { result.push({ - title: 'Agent Instance EOA', - ...getBalanceData( - walletBalances.filter( - (balance) => balance.walletAddress === wallet.address, - ), - ), + title: 'Master Safe', + ...getBalanceData(masterSafeBalances), address: wallet.address, }); - } + }); + } - if (wallet.type === WalletType.Safe) { - result.push({ - title: 'Agent Safe', - ...getBalanceData(walletBalances), - address: wallet.address, - }); - } - }); + if (!isNil(serviceAddresses)) { + serviceAddresses?.forEach((serviceWallet) => { + if (serviceWallet.type === WalletType.EOA) { + result.push({ + title: 'Agent Instance EOA', + ...getBalanceData( + walletBalances.filter( + (balance) => balance.walletAddress === serviceWallet.address, + ), + ), + address: serviceWallet.address, + }); + } + + if (serviceWallet.type === WalletType.Safe) { + result.push({ + title: 'Agent Safe', + ...getBalanceData( + walletBalances.filter( + (walletBalance) => + walletBalance.walletAddress === serviceWallet.address && + walletBalance.chainId === serviceWallet.evmChainId, + ), + ), + address: serviceWallet.address, + }); + } + }); + } return result; }, [ diff --git a/frontend/components/SettingsPage/index.tsx b/frontend/components/SettingsPage/index.tsx index a3c97cf18..8698f2364 100644 --- a/frontend/components/SettingsPage/index.tsx +++ b/frontend/components/SettingsPage/index.tsx @@ -6,7 +6,7 @@ import { useMemo } from 'react'; import { MiddlewareChain } from '@/client'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { EXPLORER_URL } from '@/constants/urls'; +import { EXPLORER_URL_BY_MIDDLEWARE_CHAIN } from '@/constants/urls'; import { Pages } from '@/enums/Pages'; import { SettingsScreen } from '@/enums/SettingsScreen'; import { useMultisig } from '@/hooks/useMultisig'; @@ -158,7 +158,7 @@ const SettingsMain = () => { <Link type="link" target="_blank" - href={`${EXPLORER_URL[MiddlewareChain.GNOSIS]}/address/${masterSafeBackupAddress}`} // TODO: dynamic by selected agent type's home_chain_id + href={`${EXPLORER_URL_BY_MIDDLEWARE_CHAIN[MiddlewareChain.GNOSIS]}/address/${masterSafeBackupAddress}`} // TODO: dynamic by selected agent type's home_chain_id > {truncatedBackupSafeAddress} {UNICODE_SYMBOLS.EXTERNAL_LINK} </Link> diff --git a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx index 7e9e7f183..48b3cc3f1 100644 --- a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx +++ b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx @@ -13,7 +13,7 @@ import { CHAIN_CONFIG } from '@/config/chains'; import { PROVIDERS } from '@/constants/providers'; import { NA } from '@/constants/symbols'; import { MIN_ETH_BALANCE_THRESHOLDS } from '@/constants/thresholds'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { SetupScreen } from '@/enums/SetupScreen'; import { useMasterBalances } from '@/hooks/useBalanceContext'; import { useSetup } from '@/hooks/useSetup'; @@ -169,9 +169,9 @@ const eoaFundingMap = { // requiredEth: MIN_ETH_BALANCE_THRESHOLDS[MiddlewareChain.BASE].safeCreation, // }, [MiddlewareChain.GNOSIS]: { - provider: PROVIDERS[ChainId.Gnosis].provider, - chainConfig: CHAIN_CONFIG[ChainId.Gnosis], - requiredEth: MIN_ETH_BALANCE_THRESHOLDS[ChainId.Gnosis].safeCreation, + provider: PROVIDERS[EvmChainId.Gnosis].provider, + chainConfig: CHAIN_CONFIG[EvmChainId.Gnosis], + requiredEth: MIN_ETH_BALANCE_THRESHOLDS[EvmChainId.Gnosis].safeCreation, }, }; @@ -238,9 +238,9 @@ export const SetupEoaFunding = () => { (balance) => balance.walletAddress === masterEoaAddress, ); const isFunded = - eoaBalance?.chainId === ChainId.Gnosis && + eoaBalance?.chainId === EvmChainId.Gnosis && eoaBalance.balance >= - MIN_ETH_BALANCE_THRESHOLDS[ChainId.Gnosis].safeCreation; + MIN_ETH_BALANCE_THRESHOLDS[EvmChainId.Gnosis].safeCreation; return ( <CardFlex> diff --git a/frontend/components/SetupPage/SetupWelcome.tsx b/frontend/components/SetupPage/SetupWelcome.tsx index 32ce62984..fc648f069 100644 --- a/frontend/components/SetupPage/SetupWelcome.tsx +++ b/frontend/components/SetupPage/SetupWelcome.tsx @@ -24,7 +24,7 @@ import { useServices } from '@/hooks/useServices'; import { useSetup } from '@/hooks/useSetup'; import { useMasterWalletContext } from '@/hooks/useWallet'; import { AccountService } from '@/service/Account'; -import { convertMiddlewareChainToChainId } from '@/utils/middlewareHelpers'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; import { FormFlex } from '../styled/FormFlex'; @@ -147,8 +147,7 @@ export const SetupWelcomeLogin = () => { masterSafes?.find( (safe) => selectedService?.home_chain && - safe.chainId === - convertMiddlewareChainToChainId(selectedService?.home_chain), + safe.evmChainId === asEvmChainId(selectedService?.home_chain), ) ?? null; const eoaBalanceEth = masterWalletBalances?.find( (balance) => balance.walletAddress === masterEoa?.address, diff --git a/frontend/components/YourWalletPage/Titles.tsx b/frontend/components/YourWalletPage/Titles.tsx index 4cea44cc9..c5f46af9b 100644 --- a/frontend/components/YourWalletPage/Titles.tsx +++ b/frontend/components/YourWalletPage/Titles.tsx @@ -84,7 +84,7 @@ export const OwnershipNftTitle = () => ( </Text> ); -export const ServiceIdTitle = () => ( +export const ServiceNftIdTitle = () => ( <Text className="text-sm text-light"> ID  <InfoTooltip placement="topRight"> diff --git a/frontend/components/YourWalletPage/YourAgent.tsx b/frontend/components/YourWalletPage/YourAgent.tsx index 87075a3e7..4d43f7d7b 100644 --- a/frontend/components/YourWalletPage/YourAgent.tsx +++ b/frontend/components/YourWalletPage/YourAgent.tsx @@ -6,7 +6,7 @@ import styled from 'styled-components'; import { OLAS_CONTRACTS } from '@/config/olasContracts'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { ContractType } from '@/enums/Contract'; import { TokenSymbol } from '@/enums/Token'; import { AgentSafe, Safe } from '@/enums/Wallet'; @@ -24,7 +24,7 @@ import { truncateAddress } from '@/utils/truncate'; import { AddressLink } from '../AddressLink'; import { InfoBreakdownList } from '../InfoBreakdown'; import { Container, infoBreakdownParentStyle } from './styles'; -import { OlasTitle, OwnershipNftTitle, ServiceIdTitle } from './Titles'; +import { OlasTitle, OwnershipNftTitle, ServiceNftIdTitle } from './Titles'; const { Text, Paragraph } = Typography; @@ -110,7 +110,7 @@ const ServiceAndNftDetails = ({ serviceConfigId: string; }) => { const serviceRegistryL2ContractAddress = - OLAS_CONTRACTS[ChainId.Gnosis][ContractType.ServiceRegistryL2].address; + OLAS_CONTRACTS[EvmChainId.Gnosis][ContractType.ServiceRegistryL2].address; return ( <NftCard> @@ -136,7 +136,7 @@ const ServiceAndNftDetails = ({ </Flex> <Flex vertical> - <ServiceIdTitle /> + <ServiceNftIdTitle /> <a href={`https://registry.olas.network/gnosis/services/${serviceConfigId}`} target="_blank" @@ -156,8 +156,8 @@ export const YourAgentWallet = ({ serviceConfigId: string; }) => { const { isLoaded } = useBalanceContext(); - const { serviceEoa, serviceSafes } = useService({ serviceConfigId }); - const { serviceSafeBalances, serviceEoaBalances, serviceStakedBalances } = + const { serviceSafes } = useService(serviceConfigId); + const { serviceSafeBalances, serviceEoaBalances } = useServiceBalances(serviceConfigId); const { @@ -235,7 +235,7 @@ export const YourAgentWallet = ({ </Flex> )} - {!isEmpty(serviceStakedBalances) && ( + {!isNil(serviceSafeNativeBalances) && ( <Flex vertical gap={8}> <InfoBreakdownList list={serviceSafeNativeBalances.map((balance) => ({ @@ -248,7 +248,7 @@ export const YourAgentWallet = ({ </Flex> )} - {serviceEoa?.address && !isEmpty(serviceEoaNativeBalances) && ( + {!isNil(serviceEoaNativeBalances) && ( <Flex vertical gap={8}> <InfoBreakdownList list={ diff --git a/frontend/components/YourWalletPage/index.tsx b/frontend/components/YourWalletPage/index.tsx index 47a2a433e..7fc36de1e 100644 --- a/frontend/components/YourWalletPage/index.tsx +++ b/frontend/components/YourWalletPage/index.tsx @@ -15,7 +15,7 @@ import { CardTitle } from '@/components/Card/CardTitle'; import { InfoBreakdownList } from '@/components/InfoBreakdown'; import { CardFlex } from '@/components/styled/CardFlex'; import { getNativeTokenSymbol } from '@/config/tokens'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { Pages } from '@/enums/Pages'; import { TokenSymbol } from '@/enums/Token'; import { @@ -69,11 +69,11 @@ const Address = () => { }; const OlasBalance = () => { - const { masterSafes } = useMasterWalletContext(); - const { walletBalances, totalStakedOlasBalance } = useBalanceContext(); + const { totalStakedOlasBalance } = useBalanceContext(); + const { masterWalletBalances } = useMasterBalances(); - const masterSafeOlasBalance: number = walletBalances - ?.filter((balance) => balance.symbol === TokenSymbol.OLAS) + const masterSafeOlasBalance = masterWalletBalances + ?.filter((walletBalance) => walletBalance.symbol === TokenSymbol.OLAS) .reduce((acc, balance) => acc + balance.balance, 0); const olasBalances = useMemo(() => { @@ -89,8 +89,7 @@ const OlasBalance = () => { ]; }, [masterSafeOlasBalance, totalStakedOlasBalance]); - if (!masterSafes) return <Skeleton />; - if (isEmpty(masterSafes)) return null; + if (isNil(masterSafeOlasBalance)) return <Skeleton />; return ( <Flex vertical gap={8}> @@ -129,14 +128,14 @@ const MasterSafeNativeBalance = () => { .reduce((acc, balance) => acc + balance.balance, 0); }, [masterEoa?.address, masterSafes, masterWalletBalances]); - const nativeTokenSymbol = getNativeTokenSymbol(ChainId.Gnosis); + const nativeTokenSymbol = getNativeTokenSymbol(EvmChainId.Gnosis); return ( <Flex vertical gap={8}> <InfoBreakdownList list={[ { - left: <Text strong>{getNativeTokenSymbol(ChainId.Gnosis)}</Text>, + left: <Text strong>{getNativeTokenSymbol(EvmChainId.Gnosis)}</Text>, leftClassName: 'text-light', right: `${balanceFormat(masterSafeNativeBalance, 2)} ${nativeTokenSymbol}`, }, @@ -165,7 +164,7 @@ const MasterEoaSignerNativeBalance = () => { }, [masterEoa, masterWalletBalances]); const nativeTokenSymbol = useMemo( - () => getNativeTokenSymbol(ChainId.Gnosis), // TODO: support multi chain + () => getNativeTokenSymbol(EvmChainId.Gnosis), // TODO: support multi chain [], ); diff --git a/frontend/config/activityCheckers.ts b/frontend/config/activityCheckers.ts index 1f77befe4..5207f61c6 100644 --- a/frontend/config/activityCheckers.ts +++ b/frontend/config/activityCheckers.ts @@ -2,7 +2,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { MECH_ACTIVITY_CHECKER_ABI } from '@/abis/mechActivityChecker'; import { REQUESTER_ACTIVITY_CHECKER_ABI } from '@/abis/requesterActivityChecker'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { MechType } from './mechs'; @@ -34,6 +34,6 @@ export const ACTIVITY_CHECKERS: { [activityCheckerType: string]: MulticallContract; }; } = { - [ChainId.Gnosis]: GNOSIS_ACTIVITY_CHECKERS, - [ChainId.Optimism]: OPTIMISM_ACTIVITY_CHECKERS, + [EvmChainId.Gnosis]: GNOSIS_ACTIVITY_CHECKERS, + [EvmChainId.Optimism]: OPTIMISM_ACTIVITY_CHECKERS, } as const; diff --git a/frontend/config/agents.ts b/frontend/config/agents.ts index 26ed492d7..b3b446982 100644 --- a/frontend/config/agents.ts +++ b/frontend/config/agents.ts @@ -1,5 +1,6 @@ +import { MiddlewareChain } from '@/client'; import { AgentType } from '@/enums/Agent'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { PredictTraderService } from '@/service/agents/PredictTrader'; // import { OptimusService } from '@/service/agents/Optimus'; import { AgentConfig } from '@/types/Agent'; @@ -12,12 +13,13 @@ export const AGENT_CONFIG: { } = { [AgentType.PredictTrader]: { name: 'Predict Trader', - homeChainId: ChainId.Gnosis, - requiresAgentSafesOn: [ChainId.Gnosis], + evmHomeChainId: EvmChainId.Gnosis, + middlewareHomeChainId: MiddlewareChain.GNOSIS, + requiresAgentSafesOn: [EvmChainId.Gnosis], agentSafeFundingRequirements: { - [ChainId.Gnosis]: 100000000000000000, + [EvmChainId.Gnosis]: 100000000000000000, }, - requiresMasterSafesOn: [ChainId.Gnosis], + requiresMasterSafesOn: [EvmChainId.Gnosis], serviceApi: PredictTraderService, }, // TODO: check optimus config diff --git a/frontend/config/chains.ts b/frontend/config/chains.ts index a38fc47f3..95a0dc3e7 100644 --- a/frontend/config/chains.ts +++ b/frontend/config/chains.ts @@ -3,7 +3,7 @@ * - add new chains to the CHAIN_CONFIGS object */ import { MiddlewareChain as MiddlewareChainId } from '@/client'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; type HttpUrl = `http${'s' | ''}://${string}`; @@ -17,7 +17,7 @@ type ChainConfig = { }; export const GNOSIS_CHAIN_CONFIG: ChainConfig = { - chainId: ChainId.Gnosis, + chainId: EvmChainId.Gnosis, name: 'Gnosis', currency: TokenSymbol.XDAI, middlewareChain: MiddlewareChainId.GNOSIS, @@ -25,7 +25,7 @@ export const GNOSIS_CHAIN_CONFIG: ChainConfig = { }; export const OPTIMISM_CHAIN_CONFIG: ChainConfig = { - chainId: ChainId.Optimism, + chainId: EvmChainId.Optimism, name: 'Optimism', currency: TokenSymbol.ETH, middlewareChain: MiddlewareChainId.OPTIMISM, @@ -33,7 +33,7 @@ export const OPTIMISM_CHAIN_CONFIG: ChainConfig = { }; export const BASE_CHAIN_CONFIG: ChainConfig = { - chainId: ChainId.Base, + chainId: EvmChainId.Base, name: 'Base', currency: TokenSymbol.ETH, middlewareChain: MiddlewareChainId.BASE, @@ -41,7 +41,7 @@ export const BASE_CHAIN_CONFIG: ChainConfig = { }; export const ETHEREUM_CHAIN_CONFIG: ChainConfig = { - chainId: ChainId.Ethereum, + chainId: EvmChainId.Ethereum, name: 'Ethereum', currency: TokenSymbol.ETH, middlewareChain: MiddlewareChainId.ETHEREUM, @@ -51,8 +51,8 @@ export const ETHEREUM_CHAIN_CONFIG: ChainConfig = { export const CHAIN_CONFIG: { [chainId: number]: ChainConfig; } = { - [ChainId.Base]: BASE_CHAIN_CONFIG, - [ChainId.Ethereum]: ETHEREUM_CHAIN_CONFIG, - [ChainId.Gnosis]: GNOSIS_CHAIN_CONFIG, - [ChainId.Optimism]: OPTIMISM_CHAIN_CONFIG, + [EvmChainId.Base]: BASE_CHAIN_CONFIG, + [EvmChainId.Ethereum]: ETHEREUM_CHAIN_CONFIG, + [EvmChainId.Gnosis]: GNOSIS_CHAIN_CONFIG, + [EvmChainId.Optimism]: OPTIMISM_CHAIN_CONFIG, } as const; diff --git a/frontend/config/mechs.ts b/frontend/config/mechs.ts index c55eb15c9..b004e0d28 100644 --- a/frontend/config/mechs.ts +++ b/frontend/config/mechs.ts @@ -3,7 +3,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { AGENT_MECH_ABI } from '@/abis/agentMech'; import { MECH_MARKETPLACE_ABI } from '@/abis/mechMarketplace'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; export enum MechType { Agent = 'mech-agent', @@ -20,7 +20,7 @@ type Mechs = { }; export const MECHS: Mechs = { - [ChainId.Gnosis]: { + [EvmChainId.Gnosis]: { [MechType.Agent]: { name: 'Agent Mech', contract: new MulticallContract( diff --git a/frontend/config/olasContracts.ts b/frontend/config/olasContracts.ts index b66f89f54..7586d202c 100644 --- a/frontend/config/olasContracts.ts +++ b/frontend/config/olasContracts.ts @@ -3,7 +3,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { SERVICE_REGISTRY_L2_ABI } from '@/abis/serviceRegistryL2'; import { SERVICE_REGISTRY_TOKEN_UTILITY_ABI } from '@/abis/serviceRegistryTokenUtility'; import { STAKING_TOKEN_PROXY_ABI } from '@/abis/stakingTokenProxy'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { ContractType } from '@/enums/Contract'; export type ContractsByType = { @@ -43,6 +43,6 @@ export const GNOSIS_OLAS_CONTRACTS: ContractsByType = { export const OLAS_CONTRACTS: { [chainId: number]: ContractsByType; } = { - [ChainId.Gnosis]: GNOSIS_OLAS_CONTRACTS, - [ChainId.Optimism]: OPTIMISM_OLAS_CONTRACTS, + [EvmChainId.Gnosis]: GNOSIS_OLAS_CONTRACTS, + [EvmChainId.Optimism]: OPTIMISM_OLAS_CONTRACTS, }; diff --git a/frontend/config/stakingPrograms/gnosis.ts b/frontend/config/stakingPrograms/gnosis.ts index e2a8361eb..5036cecab 100644 --- a/frontend/config/stakingPrograms/gnosis.ts +++ b/frontend/config/stakingPrograms/gnosis.ts @@ -2,7 +2,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { STAKING_TOKEN_PROXY_ABI } from '@/abis/stakingTokenProxy'; import { AgentType } from '@/enums/Agent'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; @@ -29,104 +29,104 @@ export const GNOSIS_STAKING_PROGRAMS: StakingProgramMap = { [StakingProgramId.PearlAlpha]: { deprecated: true, name: 'Pearl Alpha', - chainId: ChainId.Gnosis, + chainId: EvmChainId.Gnosis, agentsSupported: [AgentType.PredictTrader], stakingRequirements: { [TokenSymbol.OLAS]: 20, }, mechType: MechType.Agent, - mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, - activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], + mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, + activityChecker: ACTIVITY_CHECKERS[EvmChainId.Gnosis][MechType.Agent], contract: new MulticallContract( GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlAlpha], STAKING_TOKEN_PROXY_ABI, ), }, [StakingProgramId.PearlBeta]: { - chainId: ChainId.Gnosis, + chainId: EvmChainId.Gnosis, name: 'Pearl Beta', agentsSupported: [AgentType.PredictTrader], stakingRequirements: { [TokenSymbol.OLAS]: 40, }, mechType: MechType.Agent, - mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, - activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], + mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, + activityChecker: ACTIVITY_CHECKERS[EvmChainId.Gnosis][MechType.Agent], contract: new MulticallContract( GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta], STAKING_TOKEN_PROXY_ABI, ), }, [StakingProgramId.PearlBeta2]: { - chainId: ChainId.Gnosis, + chainId: EvmChainId.Gnosis, name: 'Pearl Beta 2', agentsSupported: [AgentType.PredictTrader], stakingRequirements: { [TokenSymbol.OLAS]: 100, }, mechType: MechType.Agent, - mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, - activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], + mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, + activityChecker: ACTIVITY_CHECKERS[EvmChainId.Gnosis][MechType.Agent], contract: new MulticallContract( GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta2], STAKING_TOKEN_PROXY_ABI, ), }, [StakingProgramId.PearlBeta3]: { - chainId: ChainId.Gnosis, + chainId: EvmChainId.Gnosis, name: 'Pearl Beta 3', agentsSupported: [AgentType.PredictTrader], stakingRequirements: { [TokenSymbol.OLAS]: 100, }, mechType: MechType.Agent, - mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, - activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], + mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, + activityChecker: ACTIVITY_CHECKERS[EvmChainId.Gnosis][MechType.Agent], contract: new MulticallContract( GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta3], STAKING_TOKEN_PROXY_ABI, ), }, [StakingProgramId.PearlBeta4]: { - chainId: ChainId.Gnosis, + chainId: EvmChainId.Gnosis, name: 'Pearl Beta 4', agentsSupported: [AgentType.PredictTrader], stakingRequirements: { [TokenSymbol.OLAS]: 100, }, mechType: MechType.Agent, - mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, - activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], + mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, + activityChecker: ACTIVITY_CHECKERS[EvmChainId.Gnosis][MechType.Agent], contract: new MulticallContract( GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta4], STAKING_TOKEN_PROXY_ABI, ), }, [StakingProgramId.PearlBeta5]: { - chainId: ChainId.Gnosis, + chainId: EvmChainId.Gnosis, name: 'Pearl Beta 5', agentsSupported: [AgentType.PredictTrader], stakingRequirements: { [TokenSymbol.OLAS]: 10, }, mechType: MechType.Agent, - mech: MECHS[ChainId.Gnosis][MechType.Agent].contract, - activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Agent], + mech: MECHS[EvmChainId.Gnosis][MechType.Agent].contract, + activityChecker: ACTIVITY_CHECKERS[EvmChainId.Gnosis][MechType.Agent], contract: new MulticallContract( GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[StakingProgramId.PearlBeta5], STAKING_TOKEN_PROXY_ABI, ), }, [StakingProgramId.PearlBetaMechMarketplace]: { - chainId: ChainId.Gnosis, + chainId: EvmChainId.Gnosis, name: 'Pearl Beta Mech Marketplace', agentsSupported: [AgentType.PredictTrader], stakingRequirements: { [TokenSymbol.OLAS]: 40, }, mechType: MechType.Marketplace, - mech: MECHS[ChainId.Gnosis][MechType.Marketplace].contract, - activityChecker: ACTIVITY_CHECKERS[ChainId.Gnosis][MechType.Marketplace], + mech: MECHS[EvmChainId.Gnosis][MechType.Marketplace].contract, + activityChecker: ACTIVITY_CHECKERS[EvmChainId.Gnosis][MechType.Marketplace], contract: new MulticallContract( GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ StakingProgramId.PearlBetaMechMarketplace diff --git a/frontend/config/stakingPrograms/index.ts b/frontend/config/stakingPrograms/index.ts index 8c22a1921..5a76eca78 100644 --- a/frontend/config/stakingPrograms/index.ts +++ b/frontend/config/stakingPrograms/index.ts @@ -1,7 +1,7 @@ import { Contract as MulticallContract } from 'ethers-multicall'; import { AgentType } from '@/enums/Agent'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; @@ -19,7 +19,7 @@ import { * Single non-chain specific staking program configuration */ export type StakingProgramConfig = { - chainId: ChainId; + chainId: EvmChainId; deprecated?: boolean; // hides program from UI unless user is already staked in this program name: string; agentsSupported: AgentType[]; @@ -37,22 +37,22 @@ export type StakingProgramMap = { }; export const STAKING_PROGRAMS: { - [chainId: number | ChainId]: StakingProgramMap; + [chainId: number | EvmChainId]: StakingProgramMap; } = { - [ChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS, + [EvmChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS, // [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS, }; export const STAKING_PROGRAM_ADDRESS: { - [chainId: number | ChainId]: Record<string, Address>; + [chainId: number | EvmChainId]: Record<string, Address>; } = { - [ChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES, + [EvmChainId.Gnosis]: GNOSIS_STAKING_PROGRAMS_CONTRACT_ADDRESSES, // [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, }; export const INITIAL_DEFAULT_STAKING_PROGRAM_IDS: { - [chainId: number | ChainId]: StakingProgramId; + [chainId: number | EvmChainId]: StakingProgramId; } = { - [ChainId.Gnosis]: StakingProgramId.PearlBeta, + [EvmChainId.Gnosis]: StakingProgramId.PearlBeta, // [ChainId.Optimism]: StakingProgramId.OptimusAlpha, }; diff --git a/frontend/config/stakingPrograms/optimism.ts b/frontend/config/stakingPrograms/optimism.ts index 9499f0720..1ade198f6 100644 --- a/frontend/config/stakingPrograms/optimism.ts +++ b/frontend/config/stakingPrograms/optimism.ts @@ -4,19 +4,9 @@ * @note Used to type chain specific staking program configs */ -import { Contract as MulticallContract } from 'ethers-multicall'; - -import { STAKING_TOKEN_PROXY_ABI } from '@/abis/stakingTokenProxy'; -import { AgentType } from '@/enums/Agent'; -import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; -import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; -import { ACTIVITY_CHECKERS } from '../activityCheckers'; -import { MECHS, MechType } from '../mechs'; -import { StakingProgramMap } from '.'; - export const OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record< string, Address @@ -24,21 +14,21 @@ export const OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES: Record< [StakingProgramId.OptimusAlpha]: '0x88996bbdE7f982D93214881756840cE2c77C4992', }; -export const OPTIMISM_STAKING_PROGRAMS: StakingProgramMap = { - [StakingProgramId.OptimusAlpha]: { - name: 'Optimus Alpha', - agentsSupported: [AgentType.Optimus], - stakingRequirements: { - [TokenSymbol.OLAS]: 40, - }, - mech: MECHS[ChainId.Optimism][MechType.Agent].contract, - activityChecker: ACTIVITY_CHECKERS[ChainId.Optimism][MechType.Agent], - chainId: ChainId.Optimism, - contract: new MulticallContract( - OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ - StakingProgramId.OptimusAlpha - ], - STAKING_TOKEN_PROXY_ABI, - ), - }, -}; +// export const OPTIMISM_STAKING_PROGRAMS: StakingProgramMap = { +// [StakingProgramId.OptimusAlpha]: { +// name: 'Optimus Alpha', +// agentsSupported: [AgentType.Optimus], +// stakingRequirements: { +// [TokenSymbol.OLAS]: 40, +// }, +// mech: MECHS[EvmChainId.Optimism][MechType.Agent].contract, +// activityChecker: ACTIVITY_CHECKERS[EvmChainId.Optimism][MechType.Agent], +// chainId: EvmChainId.Optimism, +// contract: new MulticallContract( +// OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES[ +// StakingProgramId.OptimusAlpha +// ], +// STAKING_TOKEN_PROXY_ABI, +// ), +// }, +// }; diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index c079e9722..6ccb38475 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -1,4 +1,4 @@ -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; import { Address } from '@/types/Address'; @@ -89,10 +89,10 @@ export const BASE_TOKEN_CONFIG: ChainTokenConfig = { }; export const TOKEN_CONFIG = { - [ChainId.Gnosis]: GNOSIS_TOKEN_CONFIG, - [ChainId.Optimism]: OPTIMISM_TOKEN_CONFIG, - [ChainId.Ethereum]: ETHEREUM_TOKEN_CONFIG, - [ChainId.Base]: BASE_TOKEN_CONFIG, + [EvmChainId.Gnosis]: GNOSIS_TOKEN_CONFIG, + [EvmChainId.Optimism]: OPTIMISM_TOKEN_CONFIG, + [EvmChainId.Ethereum]: ETHEREUM_TOKEN_CONFIG, + [EvmChainId.Base]: BASE_TOKEN_CONFIG, } as const; /** @@ -100,7 +100,7 @@ export const TOKEN_CONFIG = { */ export const ERC20_TOKEN_CONFIG = Object.fromEntries( Object.entries(TOKEN_CONFIG).map(([chainId, chainTokenConfig]) => [ - +chainId as ChainId, + +chainId as EvmChainId, Object.fromEntries( Object.entries(chainTokenConfig).filter( ([, tokenConfig]) => tokenConfig.tokenType === TokenType.Erc20, @@ -118,7 +118,7 @@ export const ERC20_TOKEN_CONFIG = Object.fromEntries( */ export const NATIVE_TOKEN_CONFIG = Object.fromEntries( Object.entries(TOKEN_CONFIG).map(([chainId, chainTokenConfig]) => [ - +chainId as ChainId, + +chainId as EvmChainId, Object.fromEntries( Object.entries(chainTokenConfig).filter( ([, tokenConfig]) => tokenConfig.tokenType === TokenType.NativeGas, @@ -131,8 +131,8 @@ export const NATIVE_TOKEN_CONFIG = Object.fromEntries( }; }; -export const getNativeTokenSymbol = (chainId: ChainId): TokenSymbol => +export const getNativeTokenSymbol = (chainId: EvmChainId): TokenSymbol => Object.keys(NATIVE_TOKEN_CONFIG[chainId])[0] as TokenSymbol; -export const getErc20s = (chainId: ChainId): Erc20TokenConfig[] => - Object.values(ERC20_TOKEN_CONFIG[chainId]); \ No newline at end of file +export const getErc20s = (chainId: EvmChainId): Erc20TokenConfig[] => + Object.values(ERC20_TOKEN_CONFIG[chainId]); diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index 4287debc3..4760067d2 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -64,7 +64,7 @@ export const REACT_QUERY_KEYS = { // multisigs MULTISIG_GET_OWNERS_KEY: (multisig: Safe) => - ['multisig', 'getOwners', multisig.chainId, multisig.address] as const, + ['multisig', 'getOwners', multisig.evmChainId, multisig.address] as const, MULTISIGS_GET_OWNERS_KEY: (multisigs: Safe[]) => [ 'multisigs', diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index c223a44df..1a0c792c1 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -1,7 +1,5 @@ -import { EnvProvisionType, ServiceTemplate } from '@/client'; +import { EnvProvisionType, MiddlewareChain, ServiceTemplate } from '@/client'; import { AgentType } from '@/enums/Agent'; -import { CHAIN_CONFIG } from '@/config/chains'; -import { ChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; export const SERVICE_TEMPLATES: ServiceTemplate[] = [ @@ -13,9 +11,9 @@ export const SERVICE_TEMPLATES: ServiceTemplate[] = [ image: 'https://operate.olas.network/_next/image?url=%2Fimages%2Fprediction-agent.png&w=3840&q=75', service_version: 'v0.18.4', - home_chain: CHAIN_CONFIG[ChainId.Gnosis].middlewareChain, + home_chain: MiddlewareChain.GNOSIS, configurations: { - [CHAIN_CONFIG[ChainId.Optimism].middlewareChain]: { + [MiddlewareChain.GNOSIS]: { staking_program_id: StakingProgramId.PearlBeta, // default, may be overwritten nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', rpc: 'http://localhost:8545', // overwritten diff --git a/frontend/constants/thresholds.ts b/frontend/constants/thresholds.ts index e85fa3086..57e8977ed 100644 --- a/frontend/constants/thresholds.ts +++ b/frontend/constants/thresholds.ts @@ -1,29 +1,31 @@ -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; -// TODO - -/** - * @warning must be updated to be dynamic - */ -export const MIN_ETH_BALANCE_THRESHOLDS = { - [ChainId.Gnosis]: { +// TODO: confirm eth requirements, very flaky, eth requirements will fluctuate +export const MIN_ETH_BALANCE_THRESHOLDS: Record< + EvmChainId, + { + safeCreation: number; + safeAddSigner: number; + } +> = { + [EvmChainId.Gnosis]: { safeCreation: 1.5, safeAddSigner: 0.1, }, - [ChainId.Optimism]: { + [EvmChainId.Optimism]: { safeCreation: 0.005, safeAddSigner: 0.005, }, - [ChainId.Ethereum]: { + [EvmChainId.Ethereum]: { safeCreation: 0.02, safeAddSigner: 0.02, }, - [ChainId.Base]: { + [EvmChainId.Base]: { safeCreation: 0.005, safeAddSigner: 0.005, }, }; +// TODO: update to support multi-chain, very poor implementation export const LOW_AGENT_SAFE_BALANCE = 0.5; - export const LOW_MASTER_SAFE_BALANCE = 2; diff --git a/frontend/constants/urls.ts b/frontend/constants/urls.ts index 392a37a6b..ca4a3a6f3 100644 --- a/frontend/constants/urls.ts +++ b/frontend/constants/urls.ts @@ -1,35 +1,50 @@ import { MiddlewareChain } from '@/client'; +import { EvmChainId } from '@/enums/Chain'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; -export const BACKEND_URL: string = `http://localhost:${process.env.NODE_ENV === 'production' ? 8765 : 8000}/api`; +type Url = `http${'s' | ''}://${string}`; -export const BACKEND_URL_V2: string = `http://localhost:${process.env.NODE_ENV === 'production' ? 8765 : 8000}/api/v2`; +export const BACKEND_URL: Url = `http://localhost:${process.env.NODE_ENV === 'production' ? 8765 : 8000}/api`; -export const COW_SWAP_GNOSIS_XDAI_OLAS_URL: string = +export const BACKEND_URL_V2: Url = `http://localhost:${process.env.NODE_ENV === 'production' ? 8765 : 8000}/api/v2`; + +// cowswap +export const COW_SWAP_GNOSIS_XDAI_OLAS_URL: Url = 'https://swap.cow.fi/#/100/swap/WXDAI/OLAS'; // olas.network -export const FAQ_URL = 'https://olas.network/operate#faq'; -export const DOWNLOAD_URL = 'https://olas.network/operate#download'; +export const FAQ_URL: Url = 'https://olas.network/operate#faq'; +export const DOWNLOAD_URL: Url = 'https://olas.network/operate#download'; // thegraph -export const GNOSIS_REWARDS_HISTORY_SUBGRAPH_URL = +export const GNOSIS_REWARDS_HISTORY_SUBGRAPH_URL: Url = 'https://api.studio.thegraph.com/query/81371/gnosis-pearl-rewards-history/version/latest'; // discord -export const SUPPORT_URL = +export const SUPPORT_URL: Url = 'https://discord.com/channels/899649805582737479/1244588374736502847'; -export const DISCORD_TICKET_URL = +export const DISCORD_TICKET_URL: Url = 'https://discord.com/channels/899649805582737479/1245674435160178712/1263815577240076308'; // github -export const GITHUB_API_LATEST_RELEASE = +export const GITHUB_API_LATEST_RELEASE: Url = 'https://api.github.com/repos/valory-xyz/olas-operate-app/releases/latest'; // explorers @note DO NOT END WITH `/` -export const OPTIMISM_EXPLORER_URL = 'https://optimistic.etherscan.io'; -export const GNOSIS_EXPLORER_URL = 'https://gnosisscan.io'; +export const OPTIMISM_EXPLORER_URL: Url = 'https://optimistic.etherscan.io'; +export const GNOSIS_EXPLORER_URL: Url = 'https://gnosisscan.io'; -export const EXPLORER_URL = { +export const EXPLORER_URL_BY_MIDDLEWARE_CHAIN: Record< + string | MiddlewareChain, + Url +> = { [MiddlewareChain.OPTIMISM]: OPTIMISM_EXPLORER_URL, [MiddlewareChain.GNOSIS]: GNOSIS_EXPLORER_URL, }; + +export const EXPLORER_URL_BY_EVM_CHAIN_ID: Record<number | EvmChainId, Url> = + Object.fromEntries( + Object.entries(EXPLORER_URL_BY_MIDDLEWARE_CHAIN).map( + ([middlewareChain, url]) => [asEvmChainId(middlewareChain), url], + ), + ); diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 991ca8775..2f4ad1404 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -13,25 +13,22 @@ import { import { useInterval } from 'usehooks-ts'; import { ERC20_BALANCE_OF_STRING_FRAGMENT } from '@/abis/erc20'; -import { MiddlewareServiceResponse } from '@/client'; +import { MiddlewareChain, MiddlewareServiceResponse } from '@/client'; import { TOKEN_CONFIG, TokenType } from '@/config/tokens'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { PROVIDERS } from '@/constants/providers'; -import { - LOW_AGENT_SAFE_BALANCE, - LOW_MASTER_SAFE_BALANCE, -} from '@/constants/thresholds'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { TokenSymbol } from '@/enums/Token'; -import { WalletOwnerType, Wallets, WalletType } from '@/enums/Wallet'; -import { useServices } from '@/hooks/useServices'; +import { Wallets, WalletType } from '@/enums/Wallet'; import { StakedAgentService } from '@/service/agents/StakedAgentService'; import { Address } from '@/types/Address'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; import { formatEther } from '@/utils/numberFormatters'; import { MasterWalletContext } from './MasterWalletProvider'; import { OnlineStatusContext } from './OnlineStatusProvider'; +import { ServicesContext } from './ServicesProvider'; type CrossChainStakedBalances = Array<{ serviceId: string; @@ -46,19 +43,19 @@ export const BalanceContext = createContext<{ setIsLoaded: Dispatch<SetStateAction<boolean>>; updateBalances: () => Promise<void>; setIsPaused: Dispatch<SetStateAction<boolean>>; - walletBalances: WalletBalanceResult[]; - stakedBalances: CrossChainStakedBalances; - totalOlasBalance: number; - totalEthBalance: number; - totalStakedOlasBalance: number; - lowBalances: { + walletBalances?: WalletBalanceResult[]; + stakedBalances?: CrossChainStakedBalances; + totalOlasBalance?: number; + totalEthBalance?: number; + totalStakedOlasBalance?: number; + lowBalances?: { serviceConfigId: string; - chainId: ChainId; + chainId: EvmChainId; walletAddress: Address; balance: number; expectedBalance: number; }[]; - isLowBalance: boolean; + isLowBalance?: boolean; isPaused: boolean; }>({ isLoaded: false, @@ -66,19 +63,12 @@ export const BalanceContext = createContext<{ updateBalances: async () => {}, isPaused: false, setIsPaused: () => {}, - walletBalances: [], - stakedBalances: [], - totalOlasBalance: 0, - totalEthBalance: 0, - totalStakedOlasBalance: 0, - lowBalances: [], - isLowBalance: false, }); export const BalanceProvider = ({ children }: PropsWithChildren) => { const { isOnline } = useContext(OnlineStatusContext); - const { masterWallets: wallets } = useContext(MasterWalletContext); - const { services } = useServices(); + const { masterWallets } = useContext(MasterWalletContext); + const { services } = useContext(ServicesContext); const [isLoaded, setIsLoaded] = useState<boolean>(false); const [isPaused, setIsPaused] = useState<boolean>(false); @@ -118,95 +108,13 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { }, 0); }, [stakedBalances]); - /** - * An array of wallet addresses that have low native token balances - */ - const lowBalances = useMemo(() => { - const result: { - serviceConfigId: string; - chainId: ChainId; - walletAddress: Address; - balance: number; - expectedBalance: number; - }[] = []; - - if (!services || !wallets || !walletBalances) return result; - - for (const service of services) { - const serviceId = service.service_config_id; - const serviceHomeChainId = service.home_chain_id; - - const stakedBalancesForService = stakedBalances.filter( - (balance) => - balance.serviceId === serviceId && - balance.chainId === serviceHomeChainId, - ); - - if (stakedBalancesForService.length === 0) continue; - - // Get addresses for master safe and agent home chain safe - const masterSafeWallet = wallets.find( - (wallet) => - wallet.owner === WalletOwnerType.Master && - wallet.type === WalletType.Safe && - wallet.chainId === serviceHomeChainId, - ); - - const masterSafeAddress = masterSafeWallet?.address; - const stakedAgentSafeAddress = - service.chain_configs[serviceHomeChainId]?.chain_data.multisig; - - if (!masterSafeAddress && !stakedAgentSafeAddress) continue; - - const masterSafeBalanceResult = walletBalances.find( - (balance) => - balance.walletAddress === masterSafeAddress && balance.isNative, - ); - - const stakedAgentSafeBalanceResult = walletBalances.find( - (balance) => - balance.walletAddress === stakedAgentSafeAddress && balance.isNative, - ); - - if ( - masterSafeBalanceResult && - masterSafeBalanceResult.balance < LOW_MASTER_SAFE_BALANCE - ) { - result.push({ - serviceConfigId: service.service_config_id, - chainId: serviceHomeChainId, - walletAddress: masterSafeBalanceResult.walletAddress, - balance: masterSafeBalanceResult.balance, - expectedBalance: LOW_MASTER_SAFE_BALANCE, - }); - } - - if ( - stakedAgentSafeBalanceResult && - stakedAgentSafeBalanceResult.balance < LOW_AGENT_SAFE_BALANCE - ) { - result.push({ - serviceConfigId: service.service_config_id, - chainId: serviceHomeChainId, - walletAddress: stakedAgentSafeBalanceResult.walletAddress, - balance: stakedAgentSafeBalanceResult.balance, - expectedBalance: LOW_AGENT_SAFE_BALANCE, - }); - } - } - - return result; - }, [services, stakedBalances, wallets, walletBalances]); - - const isLowBalance = useMemo(() => lowBalances?.length > 0, [lowBalances]); - const updateBalances = useCallback(async () => { - if (wallets && services) { + if (masterWallets && services) { setIsUpdatingBalances(true); try { const [walletBalancesResult, stakedBalancesResult] = await Promise.all([ - getCrossChainWalletBalances(wallets), + getCrossChainWalletBalances(masterWallets), getCrossChainStakedBalances(services), ]); @@ -219,7 +127,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { setIsUpdatingBalances(false); } } - }, [services, wallets]); + }, [services, masterWallets]); useEffect(() => { // Update balances once on load, then use interval @@ -247,8 +155,6 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { totalOlasBalance, totalEthBalance, totalStakedOlasBalance, - lowBalances, - isLowBalance, }} > {children} @@ -258,7 +164,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { export type WalletBalanceResult = { walletAddress: Address; - chainId: ChainId; + chainId: EvmChainId; symbol: TokenSymbol; isNative: boolean; balance: number; @@ -270,7 +176,7 @@ const getCrossChainWalletBalances = async ( const balanceResults: WalletBalanceResult[] = []; for (const [chainIdKey, { multicallProvider }] of Object.entries(PROVIDERS)) { - const chainId = Number(chainIdKey) as ChainId; + const chainId = Number(chainIdKey) as EvmChainId; const tokens = TOKEN_CONFIG[chainId]; if (!tokens) continue; @@ -278,7 +184,7 @@ const getCrossChainWalletBalances = async ( const relevantWallets = wallets.filter((wallet) => { const isEoa = wallet.type === WalletType.EOA; const isSafe = wallet.type === WalletType.Safe; - const isOnSameChain = isEoa || wallet.chainId === chainId; + const isOnSameChain = isEoa || wallet.evmChainId === chainId; return isEoa || (isSafe && isOnSameChain); }); @@ -338,8 +244,8 @@ const getCrossChainStakedBalances = async ( const result: CrossChainStakedBalances = []; const registryInfoPromises = services.map(async (service) => { - const serviceId = service.service_config_id; - const homeChainId = service.home_chain_id; + const serviceConfigId = service.service_config_id; + const homeChainId: MiddlewareChain = service.home_chain; const homeChainConfig = service.chain_configs[homeChainId]; const { multisig, token } = homeChainConfig.chain_data; @@ -350,11 +256,11 @@ const getCrossChainStakedBalances = async ( const registryInfo = await StakedAgentService.getServiceRegistryInfo( multisig, token, - homeChainId, + asEvmChainId(homeChainId), ); return { - serviceId, + serviceId: serviceConfigId, chainId: homeChainId, ...registryInfo, }; @@ -369,7 +275,7 @@ const getCrossChainStakedBalances = async ( result.push({ serviceId, - chainId, + chainId: asEvmChainId(chainId), ...correctBondDepositByServiceState({ olasBondBalance: bondValue, olasDepositBalance: depositValue, @@ -415,24 +321,24 @@ const correctBondDepositByServiceState = ({ case ServiceRegistryL2ServiceState.ActiveRegistration: return { olasBondBalance: 0, - olasDepositBalance: olasDepositBalance, + olasDepositBalance, }; case ServiceRegistryL2ServiceState.FinishedRegistration: case ServiceRegistryL2ServiceState.Deployed: return { - olasBondBalance: olasBondBalance, - olasDepositBalance: olasDepositBalance, + olasBondBalance, + olasDepositBalance, }; case ServiceRegistryL2ServiceState.TerminatedBonded: return { - olasBondBalance: olasBondBalance, + olasBondBalance, olasDepositBalance: 0, }; default: console.error('Invalid service state'); return { - olasBondBalance: olasBondBalance, - olasDepositBalance: olasDepositBalance, + olasBondBalance, + olasDepositBalance, }; } }; diff --git a/frontend/context/MasterWalletProvider.tsx b/frontend/context/MasterWalletProvider.tsx index 55fa87925..eed0c1756 100644 --- a/frontend/context/MasterWalletProvider.tsx +++ b/frontend/context/MasterWalletProvider.tsx @@ -13,7 +13,7 @@ import { } from '@/enums/Wallet'; import { UsePause } from '@/hooks/usePause'; import { WalletService } from '@/service/Wallet'; -import { convertMiddlewareChainToChainId } from '@/utils/middlewareHelpers'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; import { OnlineStatusContext } from './OnlineStatusProvider'; @@ -45,7 +45,7 @@ const transformMiddlewareWalletResponse = ( const masterSafes: MasterSafe[] = Object.entries(data.safes).map( ([middlewareChain, address]) => ({ address, - chainId: convertMiddlewareChainToChainId(middlewareChain), + evmChainId: asEvmChainId(middlewareChain), owner: WalletOwnerType.Master, type: WalletType.Safe, }), diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index b39a78898..efa61ce68 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -18,6 +18,7 @@ import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useStore } from '@/hooks/useStore'; import { StakingRewardsInfoSchema } from '@/types/Autonolas'; +import { asMiddlewareChain } from '@/utils/middlewareHelpers'; import { OnlineStatusContext } from './OnlineStatusProvider'; import { StakingProgramContext } from './StakingProgramProvider'; @@ -41,7 +42,7 @@ export const RewardContext = createContext<{ }); const currentAgent = AGENT_CONFIG.trader; // TODO: replace with dynamic agent selection -const currentChainId = GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with dynamic chain selection +const currentChainId = GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with selectedAgentConfig.chainId /** * hook to fetch staking rewards details @@ -51,11 +52,13 @@ const useStakingRewardsDetails = () => { const { activeStakingProgramId } = useContext(StakingProgramContext); const { selectedService } = useServices(); + const { service } = useService(selectedService?.service_config_id); + const serviceConfigId = selectedService?.service_config_id; - const { service } = useService({ serviceConfigId }); // fetch chain data from the selected service - const chainData = service?.chain_configs[currentChainId].chain_data; + const chainData = + service?.chain_configs[asMiddlewareChain(currentChainId)].chain_data; const multisig = chainData?.multisig; const token = chainData?.token; diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index dd4c8ee0b..4232eb4e2 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -10,12 +10,12 @@ import { useState, } from 'react'; -import { MiddlewareServiceResponse } from '@/client'; +import { MiddlewareChain, MiddlewareServiceResponse } from '@/client'; import { AGENT_CONFIG } from '@/config/agents'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { AgentType } from '@/enums/Agent'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { AgentEoa, AgentSafe, @@ -28,13 +28,21 @@ import { ServicesService } from '@/service/Services'; import { AgentConfig } from '@/types/Agent'; import { Service } from '@/types/Service'; import { Maybe } from '@/types/Util'; +import { asEvmChainId, asMiddlewareChain } from '@/utils/middlewareHelpers'; import { OnlineStatusContext } from './OnlineStatusProvider'; type ServicesContextType = { services?: MiddlewareServiceResponse[]; - serviceAddresses?: AgentWallets; - servicesByChain?: Record<number, MiddlewareServiceResponse[]>; + serviceWallets?: AgentWallets; + servicesByMiddlewareChain?: Record< + string | MiddlewareChain, + MiddlewareServiceResponse[] + >; + servicesByEvmChainId?: Record< + number | EvmChainId, + MiddlewareServiceResponse[] + >; selectService: (serviceUuid: string) => void; selectedService?: Service; selectedAgentConfig: AgentConfig; @@ -107,23 +115,38 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { return config; }, [selectedAgentType]); - const servicesByChain = useMemo(() => { + const servicesByMiddlewareChain = useMemo(() => { if (!isFetched) return; if (!services) return; - return Object.keys(ChainId).reduce( - ( - acc: Record<number, MiddlewareServiceResponse[]>, - chainIdKey: string, - ) => { - const chainIdNumber = +chainIdKey; - acc[chainIdNumber] = services.filter( - (service: MiddlewareServiceResponse) => - service.chain_configs[chainIdNumber], - ); - return acc; - }, - {}, - ); + return Object.keys(EvmChainId).reduce< + Record<string | MiddlewareChain, MiddlewareServiceResponse[]> + >((acc, evmChainIdKey) => { + const middlewareChain = asMiddlewareChain( + EvmChainId[evmChainIdKey as keyof typeof EvmChainId], + ); + + acc[middlewareChain] = services.filter( + (service: MiddlewareServiceResponse) => + service.chain_configs[middlewareChain], + ); + return acc; + }, {}); + }, [isFetched, services]); + + const servicesByEvmChainId = useMemo(() => { + if (!isFetched) return; + if (!services) return; + return Object.keys(EvmChainId).reduce< + Record<number, MiddlewareServiceResponse[]> + >((acc, evmChainIdKey) => { + const evmChainId = EvmChainId[evmChainIdKey as keyof typeof EvmChainId]; + + acc[evmChainId] = services.filter( + (service: MiddlewareServiceResponse) => + service.chain_configs[asMiddlewareChain(evmChainId)], + ); + return acc; + }, {}); }, [isFetched, services]); const serviceAddresses = useMemo(() => { @@ -135,9 +158,14 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { return [ ...acc, ...Object.keys(service.chain_configs).reduce( - (acc: AgentWallets, chainIdKey: string) => { - const chainId = +chainIdKey; - const chainConfig = service.chain_configs[chainId]; + (acc: AgentWallets, middlewareChainKey: string) => { + const middlewareChain = + MiddlewareChain[ + middlewareChainKey as keyof typeof MiddlewareChain + ]; + + const chainConfig = service.chain_configs[middlewareChain]; + if (!chainConfig) return acc; const instances = chainConfig.chain_data.instances; @@ -161,7 +189,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { address: multisig, type: WalletType.Safe, owner: WalletOwnerType.Agent, - chainId, + evmChainId: asEvmChainId(middlewareChainKey), } as AgentSafe); } @@ -196,8 +224,9 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { <ServicesContext.Provider value={{ services, - serviceAddresses, - servicesByChain, + serviceWallets: serviceAddresses, + servicesByMiddlewareChain, + servicesByEvmChainId, isError, isFetched, isLoading, diff --git a/frontend/context/StakingContractDetailsProvider.tsx b/frontend/context/StakingContractDetailsProvider.tsx index 62befaa50..863109fd2 100644 --- a/frontend/context/StakingContractDetailsProvider.tsx +++ b/frontend/context/StakingContractDetailsProvider.tsx @@ -17,6 +17,7 @@ import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useStakingProgram } from '@/hooks/useStakingProgram'; import { StakingContractDetails } from '@/types/Autonolas'; +import { asMiddlewareChain } from '@/utils/middlewareHelpers'; import { StakingProgramContext } from './StakingProgramProvider'; @@ -26,7 +27,7 @@ import { StakingProgramContext } from './StakingProgramProvider'; const useAllStakingContractDetails = () => { const { allStakingProgramIds } = useStakingProgram(); const { selectedAgentConfig } = useServices(); - const { serviceApi, homeChainId } = selectedAgentConfig; + const { serviceApi, evmHomeChainId: homeChainId } = selectedAgentConfig; const queryResults = useQueries({ queries: allStakingProgramIds.map((programId) => ({ @@ -72,27 +73,32 @@ const useAllStakingContractDetails = () => { /** * hook to get staking contract details by staking program */ -const useStakingContractDetailsByStakingProgram = ( - serviceId: Maybe<number>, - stakingProgramId: Maybe<StakingProgramId>, - isPaused?: boolean, -) => { +const useStakingContractDetailsByStakingProgram = ({ + serviceNftTokenId, + stakingProgramId, + isPaused, +}: { + serviceNftTokenId: Maybe<number>; + stakingProgramId: Maybe<StakingProgramId>; + isPaused?: boolean; +}) => { const { selectedAgentConfig } = useServices(); - const { serviceApi, homeChainId: chainId } = selectedAgentConfig; + const { serviceApi, evmHomeChainId: chainId } = selectedAgentConfig; return useQuery({ queryKey: REACT_QUERY_KEYS.STAKING_CONTRACT_DETAILS_BY_STAKING_PROGRAM_KEY( chainId, - serviceId!, + serviceNftTokenId!, stakingProgramId!, ), queryFn: async () => { return await serviceApi.getStakingContractDetailsByServiceIdStakingProgram( - serviceId!, + serviceNftTokenId!, stakingProgramId!, chainId, ); }, - enabled: !!serviceId && !!stakingProgramId && !!chainId && !isPaused, + enabled: + !!serviceNftTokenId && !!stakingProgramId && !!chainId && !isPaused, refetchInterval: !isPaused ? FIVE_SECONDS_INTERVAL : () => false, refetchOnWindowFocus: false, }); @@ -132,28 +138,21 @@ export const StakingContractDetailsProvider = ({ children, }: PropsWithChildren) => { const [isPaused, setIsPaused] = useState(false); - const { - selectedService, - selectedAgentConfig, - isFetched: isLoaded, - } = useServices(); - const serviceConfigId = - selectedService?.service_config_id; - const { service } = useService({ serviceConfigId }); - const serviceId = - service?.chain_configs?.[selectedAgentConfig?.homeChainId]?.chain_data - ?.token; + const { selectedService, selectedAgentConfig } = useServices(); + const { service } = useService(selectedService?.service_config_id); const { activeStakingProgramId } = useContext(StakingProgramContext); + const { data: activeStakingContractDetails, isLoading: isActiveStakingContractDetailsLoading, refetch: refetchActiveStakingContract, - } = useStakingContractDetailsByStakingProgram( - serviceId, - activeStakingProgramId, - isPaused, - ); + } = useStakingContractDetailsByStakingProgram({ + serviceNftTokenId: + service?.chain_configs[asMiddlewareChain(selectedAgentConfig.evmHomeChainId)] + .chain_data.token, + stakingProgramId: activeStakingProgramId, + }); const { allStakingContractDetailsRecord, isAllStakingContractDetailsLoaded } = useAllStakingContractDetails(); diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index 457b39523..107794424 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -22,40 +22,43 @@ export const StakingProgramContext = createContext<{ /** * hook to get the active staking program id */ -const useGetActiveStakingProgramId = (serviceId: Maybe<number>) => { +const useGetActiveStakingProgramId = (serviceNftTokenId: Maybe<number>) => { const queryClient = useQueryClient(); const { selectedAgentConfig } = useServices(); - const { serviceApi, homeChainId } = selectedAgentConfig; + const { serviceApi, evmHomeChainId: homeChainId } = selectedAgentConfig; const response = useQuery({ - queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(homeChainId, serviceId!), + queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY( + homeChainId, + serviceNftTokenId!, + ), queryFn: async () => { const response = await serviceApi.getCurrentStakingProgramByServiceId( - serviceId!, + serviceNftTokenId!, homeChainId, ); return ( response || - INITIAL_DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.homeChainId] + INITIAL_DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.evmHomeChainId] ); }, - enabled: !!homeChainId && !!serviceId, - refetchInterval: serviceId ? FIVE_SECONDS_INTERVAL : false, + enabled: !!homeChainId && !!serviceNftTokenId, + refetchInterval: serviceNftTokenId ? FIVE_SECONDS_INTERVAL : false, }); const setActiveStakingProgramId = useCallback( (stakingProgramId: Nullable<StakingProgramId>) => { - if (!serviceId) return; + if (!serviceNftTokenId) return; if (!stakingProgramId) return; // update the active staking program id in the cache queryClient.setQueryData( - REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(homeChainId, serviceId), + REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(homeChainId, serviceNftTokenId), stakingProgramId, ); }, - [queryClient, homeChainId, serviceId], + [queryClient, homeChainId, serviceNftTokenId], ); return { ...response, setActiveStakingProgramId }; @@ -74,17 +77,13 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { } = useServices(); const serviceConfigId = isLoaded && selectedService ? selectedService?.service_config_id : ''; - const { service } = useService({ serviceConfigId }); + const { service } = useService(serviceConfigId); + + const serviceNftTokenId = + service?.chain_configs[service?.home_chain]?.chain_data?.token; - // fetch chain data from the selected service - const chainId = - selectedService?.home_chain && - convertMiddlewareChainToChainId(selectedService?.home_chain); - const serviceId = chainId - ? service?.chain_configs?.[chainId].chain_data?.token - : null; const { isLoading: isStakingProgramsLoading, data: activeStakingProgramId } = - useGetActiveStakingProgramId(serviceId); + useGetActiveStakingProgramId(serviceNftTokenId); return ( <StakingProgramContext.Provider @@ -93,7 +92,7 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { !isStakingProgramsLoading && !!activeStakingProgramId, activeStakingProgramId, initialDefaultStakingProgramId: - INITIAL_DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.homeChainId], + INITIAL_DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.evmHomeChainId], }} > {children} diff --git a/frontend/enums/Chain.ts b/frontend/enums/Chain.ts index 4740a6342..ea6ae2d3e 100644 --- a/frontend/enums/Chain.ts +++ b/frontend/enums/Chain.ts @@ -1,13 +1,13 @@ -export enum ChainId { +export enum EvmChainId { Ethereum = 1, Optimism = 100, Gnosis = 10, Base = 8453, } -export const ChainName = { - [ChainId.Ethereum]: 'Ethereum', - [ChainId.Optimism]: 'Optimism', - [ChainId.Gnosis]: 'Gnosis', - [ChainId.Base]: 'Base', +export const EvmChainName = { + [EvmChainId.Ethereum]: 'Ethereum', + [EvmChainId.Optimism]: 'Optimism', + [EvmChainId.Gnosis]: 'Gnosis', + [EvmChainId.Base]: 'Base', }; diff --git a/frontend/enums/Wallet.ts b/frontend/enums/Wallet.ts index 66a9b9102..ed52a5a6d 100644 --- a/frontend/enums/Wallet.ts +++ b/frontend/enums/Wallet.ts @@ -1,6 +1,6 @@ import { Address } from '@/types/Address'; -import { ChainId } from './Chain'; +import { EvmChainId } from './Chain'; export enum WalletType { Safe = 'multisig', @@ -11,6 +11,7 @@ export enum WalletOwnerType { Agent = 'agent', } +// types of wallet export type Eoa = { address: Address; type: WalletType.EOA; @@ -19,9 +20,10 @@ export type Eoa = { export type Safe = { address: Address; type: WalletType.Safe; - chainId: ChainId; + evmChainId: EvmChainId; }; +// owned eoas export type MasterEoa = Eoa & { owner: WalletOwnerType.Master; }; @@ -30,6 +32,7 @@ export type AgentEoa = Eoa & { owner: WalletOwnerType.Agent; }; +// owned safes export type MasterSafe = Safe & { owner: WalletOwnerType.Master; }; @@ -38,11 +41,12 @@ export type AgentSafe = Safe & { owner: WalletOwnerType.Agent; }; +// generic wallets export type MasterWallet = MasterEoa | MasterSafe; export type AgentWallet = AgentEoa | AgentSafe; +export type Wallet = MasterWallet | AgentWallet; +// collections of wallets // TODO: probably not needed export type MasterWallets = MasterWallet[]; export type AgentWallets = AgentWallet[]; - -export type Wallet = MasterWallet | AgentWallet; export type Wallets = Wallet[]; diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index d0f62d54a..2cbcf149c 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -1,6 +1,7 @@ import { useContext, useMemo } from 'react'; import { BalanceContext, WalletBalanceResult } from '@/context/BalanceProvider'; +import { Optional } from '@/types/Util'; import { useService } from './useService'; import { useMasterWalletContext } from './useWallet'; @@ -13,9 +14,8 @@ export const useBalanceContext = () => useContext(BalanceContext); * @returns */ export const useServiceBalances = (serviceConfigId: string | undefined) => { - const { flatAddresses, serviceSafes, serviceEoa } = useService({ - serviceConfigId, - }); + const { flatAddresses, serviceSafes, serviceEoa } = + useService(serviceConfigId); const { walletBalances, stakedBalances } = useBalanceContext(); /** @@ -32,7 +32,7 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { /** * Cross-chain unstaked balances in service safes */ - const serviceSafeBalances = useMemo<WalletBalanceResult[]>( + const serviceSafeBalances = useMemo<Optional<WalletBalanceResult[]>>( () => walletBalances?.filter((balance) => serviceSafes.find(({ address }) => balance.walletAddress === address), @@ -43,7 +43,7 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { /** * Cross-chain unstaked balances in service eoa (signer) */ - const serviceEoaBalances = useMemo<WalletBalanceResult[]>( + const serviceEoaBalances = useMemo<Optional<WalletBalanceResult[]>>( () => walletBalances?.filter( (balance) => balance.walletAddress === serviceEoa?.address, @@ -56,10 +56,13 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { * Across all service wallets, including eoa * @note NOT STAKED BALANCES */ - const serviceWalletBalances = useMemo( - () => [...serviceSafeBalances, ...serviceEoaBalances], - [serviceEoaBalances, serviceSafeBalances], - ); + const serviceWalletBalances = useMemo<Optional<WalletBalanceResult[]>>(() => { + let result; + if (serviceSafeBalances || serviceEoaBalances) { + result = [...(serviceSafeBalances || []), ...(serviceEoaBalances || [])]; + } + return result; + }, [serviceEoaBalances, serviceSafeBalances]); return { serviceWalletBalances, @@ -87,8 +90,7 @@ export const useMasterBalances = () => { // [masterSafes, stakedBalances], // ); - // TODO: use flatAddresses for consistency - const masterSafeBalances = useMemo<WalletBalanceResult[]>( + const masterSafeBalances = useMemo<Optional<WalletBalanceResult[]>>( () => walletBalances?.filter((balance) => masterSafes?.find(({ address }) => balance.walletAddress === address), @@ -96,7 +98,7 @@ export const useMasterBalances = () => { [masterSafes, walletBalances], ); - const masterEoaBalances = useMemo<WalletBalanceResult[]>( + const masterEoaBalances = useMemo<Optional<WalletBalanceResult[]>>( () => walletBalances?.filter( (balance) => balance.walletAddress === masterEoa?.address, @@ -107,10 +109,13 @@ export const useMasterBalances = () => { /** * Unstaked balances across master safes and eoas */ - const masterWalletBalances = useMemo( - () => [...masterSafeBalances, ...masterEoaBalances], - [masterEoaBalances, masterSafeBalances], - ); + const masterWalletBalances = useMemo<Optional<WalletBalanceResult[]>>(() => { + let result; + if (masterSafeBalances || masterEoaBalances) { + result = [...(masterSafeBalances || []), ...(masterEoaBalances || [])]; + } + return result; + }, [masterEoaBalances, masterSafeBalances]); return { masterWalletBalances, diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index e1d890209..6fdd6a713 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -2,7 +2,7 @@ import { useQueryClient } from '@tanstack/react-query'; import { useMemo } from 'react'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { Eoa, WalletType } from '@/enums/Wallet'; import { Address } from '@/types/Address'; import { Optional } from '@/types/Util'; @@ -20,36 +20,39 @@ const useAddressesLogs = () => { isFetching: masterWalletsIsFetching, } = useMasterWalletContext(); - const { owners: allMasterSafeOwners, ownersIsPending } = - useMultisigs(masterSafes); + const { + masterSafesOwners: masterSafesOwners, + masterSafesOwnersIsPending: masterSafesOwnersIsPending, + } = useMultisigs(masterSafes); const backupEoas = useMemo<Optional<Eoa[]>>(() => { if (!masterEoa) return; - if (!allMasterSafeOwners) return; + if (!masterSafesOwners) return; - const result = allMasterSafeOwners - .map((masterSafeOwners) => - masterSafeOwners.owners + const result = masterSafesOwners + .map((masterSafeOwners) => { + const { owners, safeAddress, evmChainId } = masterSafeOwners; + return owners .filter((owner): owner is Address => owner !== masterEoa.address) - .map<Eoa>((owner) => ({ - address: owner, + .map<Eoa>((address) => ({ + address, type: WalletType.EOA, - safeAddress: masterSafeOwners.safeAddress, - chainId: masterSafeOwners.chainId, - })), - ) + safeAddress, + evmChainId, + })); + }) .flat(); return result; - }, [allMasterSafeOwners, masterEoa]); + }, [masterSafesOwners, masterEoa]); return { - isLoaded: masterWalletsIsFetching && ownersIsPending, + isLoaded: masterWalletsIsFetching && masterSafesOwnersIsPending, data: [ { masterEoa: masterEoa ?? 'undefined' }, { masterSafes: - masterSafes?.find((safe) => safe.chainId === ChainId.Gnosis) ?? + masterSafes?.find((safe) => safe.evmChainId === EvmChainId.Gnosis) ?? 'undefined', }, { masterSafeBackups: backupEoas ?? 'undefined' }, @@ -84,7 +87,7 @@ const useServicesLogs = () => { const { getQueryData } = useQueryClient(); return { - isLoaded: isLoaded, + isLoaded, data: { services: services?.map((item) => ({ diff --git a/frontend/hooks/useMultisig.ts b/frontend/hooks/useMultisig.ts index c3cf6326b..26aeed5ce 100644 --- a/frontend/hooks/useMultisig.ts +++ b/frontend/hooks/useMultisig.ts @@ -7,6 +7,7 @@ import { GNOSIS_SAFE_ABI } from '@/abis/gnosisSafe'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { PROVIDERS } from '@/constants/providers'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; +import { EvmChainId } from '@/enums/Chain'; import { Safe } from '@/enums/Wallet'; import { Address } from '@/types/Address'; @@ -31,7 +32,7 @@ export const useMultisig = (safe?: Safe) => { const contract = new Contract( safe.address, GNOSIS_SAFE_ABI, - PROVIDERS[safe.chainId].provider, + PROVIDERS[safe.evmChainId].provider, ); return contract.functions.getOwners() as Promise<Address[]>; }, @@ -41,26 +42,27 @@ export const useMultisig = (safe?: Safe) => { return { owners, ownersIsFetched, ownersIsPending }; }; +type MultisigOwners = { + safeAddress: Address; + evmChainId: EvmChainId; + owners: Address[]; +}; + /** * Hook to fetch from an array of multisigs */ export const useMultisigs = (safes?: Safe[]) => { const { - data: owners, - isFetched: ownersIsFetched, - isPending: ownersIsPending, - } = useQuery<{ safeAddress: string; chainId: number; owners: string[] }[]>({ + data: masterSafesOwners, + isFetched: masterSafesOwnersIsFetched, + isPending: masterSafesOwnersIsPending, + } = useQuery<MultisigOwners[]>({ enabled: !isNil(safes) && !isEmpty(safes), queryKey: safes ? REACT_QUERY_KEYS.MULTISIGS_GET_OWNERS_KEY(safes) : [], - queryFn: async (): Promise< - { - safeAddress: string; - chainId: number; - owners: string[]; - }[] - > => { + queryFn: async (): Promise<MultisigOwners[]> => { if (!safes || isEmpty(safes)) return []; - const results: { + + const contractCallsByChainId: { [chainId: number]: { safeAddress: string; contractCall: ContractCall; @@ -68,35 +70,37 @@ export const useMultisigs = (safes?: Safe[]) => { } = {}; // Step 1: Group safes by chainId and prepare contract calls - for (const [chainId] of Object.entries(PROVIDERS)) { + for (const [evmChainIdKey] of Object.entries(PROVIDERS)) { const safesOnChainId = safes.filter( - (safe) => safe.chainId === +chainId, + (safe) => safe.evmChainId === <EvmChainId>+evmChainIdKey, ); if (safesOnChainId.length === 0) { continue; } - results[+chainId] = safesOnChainId.map((safe) => ({ - safeAddress: safe.address, - contractCall: new MulticallContract( - safe.address, - GNOSIS_SAFE_ABI, - ).getOwners(), - })); + contractCallsByChainId[<EvmChainId>+evmChainIdKey] = safesOnChainId.map( + (safe) => ({ + safeAddress: safe.address, + contractCall: new MulticallContract( + safe.address, + GNOSIS_SAFE_ABI, + ).getOwners(), + }), + ); } // Step 2: Execute multicall and gather results - const output: { - safeAddress: string; - chainId: number; - owners: string[]; - }[] = []; + const output: MultisigOwners[] = []; - for (const [chainId, calls] of Object.entries(results)) { - const provider = PROVIDERS[+chainId]?.multicallProvider; + for (const [evmChainIdKey, calls] of Object.entries( + contractCallsByChainId, + )) { + const evmChainId = <EvmChainId>+evmChainIdKey; + + const provider = PROVIDERS[evmChainId]?.multicallProvider; if (!provider) { - console.error(`No provider found for chainId ${chainId}`); + console.error(`No provider found for chainId ${evmChainId}`); continue; } @@ -107,9 +111,10 @@ export const useMultisigs = (safes?: Safe[]) => { // Combine results into the output ownersArray.forEach((owners, index) => { + const safeAddress = <Address>calls[index].safeAddress; output.push({ - safeAddress: calls[index].safeAddress, - chainId: +chainId, + safeAddress, + evmChainId, owners, }); }); @@ -120,5 +125,9 @@ export const useMultisigs = (safes?: Safe[]) => { refetchInterval: FIVE_SECONDS_INTERVAL, }); - return { owners, ownersIsFetched, ownersIsPending }; + return { + masterSafesOwners, + masterSafesOwnersIsFetched, + masterSafesOwnersIsPending, + }; }; diff --git a/frontend/hooks/useNeedsFunds.ts b/frontend/hooks/useNeedsFunds.ts index f21742e12..51e8cea7a 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -13,7 +13,7 @@ import { useStore } from './useStore'; export const useNeedsFunds = (serviceConfigId?: string) => { const { storeState } = useStore(); - const { service } = useService({ serviceConfigId }); + const { service } = useService(serviceConfigId); const { isLoaded: isBalanceLoaded, walletBalances } = useBalanceContext(); const { masterSafeBalances } = useMasterBalances(); diff --git a/frontend/hooks/useNotifyOnNewEpoch.ts b/frontend/hooks/useNotifyOnNewEpoch.ts index 44eb64d4e..dd7f40c2b 100644 --- a/frontend/hooks/useNotifyOnNewEpoch.ts +++ b/frontend/hooks/useNotifyOnNewEpoch.ts @@ -18,9 +18,7 @@ type EpochStatusNotification = { export const useNotifyOnNewEpoch = () => { const { showNotification } = useElectronApi(); const { selectedService } = useServices(); - const { isServiceRunning } = useService({ - serviceConfigId: selectedService?.service_config_id, - }); + const { isServiceRunning } = useService(selectedService?.service_config_id); const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded } = useActiveStakingContractInfo(); diff --git a/frontend/hooks/useRewardsHistory.ts b/frontend/hooks/useRewardsHistory.ts index 392da9431..82194d1d1 100644 --- a/frontend/hooks/useRewardsHistory.ts +++ b/frontend/hooks/useRewardsHistory.ts @@ -9,9 +9,10 @@ import { z } from 'zod'; import { STAKING_PROGRAM_ADDRESS } from '@/config/stakingPrograms'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { GNOSIS_REWARDS_HISTORY_SUBGRAPH_URL } from '@/constants/urls'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { Address } from '@/types/Address'; import { Nullable } from '@/types/Util'; +import { asMiddlewareChain } from '@/utils/middlewareHelpers'; import { useService } from './useService'; import { useServices } from './useServices'; @@ -92,7 +93,7 @@ export type Checkpoint = { const useTransformCheckpoints = () => { const { selectedAgentConfig } = useServices(); - const { serviceApi: agent, homeChainId: chainId } = selectedAgentConfig; + const { serviceApi: agent, evmHomeChainId: chainId } = selectedAgentConfig; return useCallback( ( @@ -163,7 +164,10 @@ type CheckpointsResponse = { checkpoints: CheckpointResponse[] }; /** * hook to fetch rewards history for all contracts */ -const useContractCheckpoints = (chainId: ChainId, serviceId: Maybe<number>) => { +const useContractCheckpoints = ( + chainId: EvmChainId, + serviceId: Maybe<number>, +) => { const transformCheckpoints = useTransformCheckpoints(); return useQuery({ @@ -234,10 +238,12 @@ const useContractCheckpoints = (chainId: ChainId, serviceId: Maybe<number>) => { export const useRewardsHistory = () => { const { selectedService, selectedAgentConfig } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; const serviceConfigId = selectedService?.service_config_id; - const { service } = useService({ serviceConfigId }); - const serviceId = service?.chain_configs[homeChainId].chain_data?.token; + const { service } = useService(serviceConfigId); + + const serviceNftTokenId = + service?.chain_configs[asMiddlewareChain(homeChainId)].chain_data?.token; const { isError, @@ -245,7 +251,7 @@ export const useRewardsHistory = () => { isFetching, refetch, data: contractCheckpoints, - } = useContractCheckpoints(homeChainId, serviceId); + } = useContractCheckpoints(homeChainId, serviceNftTokenId); const epochSortedCheckpoints = useMemo<Checkpoint[]>( () => @@ -302,8 +308,8 @@ export const useRewardsHistory = () => { }, [isLoading, isFetching, epochSortedCheckpoints, contractCheckpoints]); useEffect(() => { - serviceId && refetch(); - }, [refetch, serviceId]); + serviceNftTokenId && refetch(); + }, [refetch, serviceNftTokenId]); return { isError, diff --git a/frontend/hooks/useService.ts b/frontend/hooks/useService.ts index de53bc8e8..c1c6ca876 100644 --- a/frontend/hooks/useService.ts +++ b/frontend/hooks/useService.ts @@ -3,12 +3,13 @@ import { useMemo } from 'react'; import { MiddlewareBuildingStatuses, + MiddlewareChain, MiddlewareDeploymentStatus, MiddlewareRunningStatuses, MiddlewareTransitioningStatuses, } from '@/client'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { AgentEoa, AgentSafe, @@ -17,11 +18,12 @@ import { WalletType, } from '@/enums/Wallet'; import { Address } from '@/types/Address'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; import { useServices } from './useServices'; type ServiceChainIdAddressRecord = { - [chainId: number]: { + [evmChainId: number]: { agentSafe?: Address; agentEoas?: Address[]; }; @@ -30,14 +32,10 @@ type ServiceChainIdAddressRecord = { /** * Hook for interacting with a single service. */ -export const useService = ({ - serviceConfigId = '', -}: { - serviceConfigId?: string; -}) => { +export const useService = (serviceConfigId?: string) => { const { services, isFetched: isLoaded } = useServices(); const queryClient = useQueryClient(); - // const { wallets } = useMasterWalletContext(); + // const { wallets } = useMasterWalletContext(); // TODO: implement const service = useMemo(() => { return services?.find( @@ -47,9 +45,8 @@ export const useService = ({ // TODO: quick hack to fix for refactor (only predict), will make it dynamic later const serviceWallets: AgentWallets = useMemo(() => { - if (!service?.chain_configs[ChainId.Gnosis]) return []; - - const chainConfig = service?.chain_configs[ChainId.Gnosis]; + const chainConfig = service?.chain_configs[MiddlewareChain.GNOSIS]; + if (!chainConfig) return []; return [ ...(chainConfig.chain_data.instances ?? []).map( @@ -66,7 +63,7 @@ export const useService = ({ address: chainConfig.chain_data.multisig, owner: WalletOwnerType.Agent, type: WalletType.Safe, - chainId: ChainId.Gnosis, + evmChainId: EvmChainId.Gnosis, } as AgentSafe, ] : []), @@ -80,17 +77,15 @@ export const useService = ({ // group multisigs by chainId const addressesByChainId: ServiceChainIdAddressRecord = Object.keys( chainData, - ).reduce((acc, chainIdKey) => { - const chainId = +chainIdKey; - - const chain = chainData[chainId]; - if (!chain) return acc; + ).reduce((acc, middlewareChain) => { + const { multisig, instances } = + chainData[middlewareChain as keyof typeof chainData].chain_data; - const { multisig, instances } = chain.chain_data; + const evmChainId = asEvmChainId(middlewareChain); return { ...acc, - [chainId]: { + [evmChainId]: { agentSafe: multisig, agentEoas: instances, }, @@ -134,15 +129,23 @@ export const useService = ({ * Overrides the deployment status of the service in the cache. * @note Overwrite is only temporary if ServicesContext is polling */ - const setDeploymentStatus = (deploymentStatus?: MiddlewareDeploymentStatus) => + const setDeploymentStatus = ( + deploymentStatus?: MiddlewareDeploymentStatus, + ) => { + if (!serviceConfigId) throw new Error('Service config ID is required'); + if (!deploymentStatus) throw new Error('Deployment status is required'); + queryClient.setQueryData( REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY(serviceConfigId), deploymentStatus, ); + }; - const deploymentStatus = queryClient.getQueryData< - MiddlewareDeploymentStatus | undefined - >(REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY(serviceConfigId)); + const deploymentStatus = serviceConfigId + ? queryClient.getQueryData<MiddlewareDeploymentStatus | undefined>( + REACT_QUERY_KEYS.SERVICE_DEPLOYMENT_STATUS_KEY(serviceConfigId), + ) + : undefined; /** @note deployment is transitioning from stopped to deployed (and vice versa) */ const isServiceTransitioning = deploymentStatus diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index 980edf63a..34680c827 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -21,8 +21,9 @@ export const useStakingProgram = () => { activeStakingProgramId, initialDefaultStakingProgramId, } = useContext(StakingProgramContext); + const { selectedAgentConfig } = useServices(); - const { homeChainId } = selectedAgentConfig; + const { evmHomeChainId: homeChainId } = selectedAgentConfig; const allStakingProgramsKeys = Object.keys(STAKING_PROGRAMS[homeChainId]); const allStakingProgramNameAddressPair = STAKING_PROGRAM_ADDRESS[homeChainId]; diff --git a/frontend/package.json b/frontend/package.json index cb0ae8066..08d1df4e6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -30,8 +30,8 @@ "@types/node": "20.14.10", "@types/react": "18.3.3", "@types/react-dom": "^18", - "@typescript-eslint/eslint-plugin": "^7.0.1", - "@typescript-eslint/parser": "^7.0.1", + "@typescript-eslint/eslint-plugin": "^7.18.0", + "@typescript-eslint/parser": "^7.18.0", "eslint": "^8.56.0", "eslint-config-next": "14.1.0", "eslint-config-prettier": "^9.1.0", @@ -45,7 +45,7 @@ "jest-environment-jsdom": "^29.7.0", "prettier": "^3.2.5", "ts-node": "^10.9.2", - "typescript": "5.5.3" + "typescript": "5.3.x" }, "name": "olas-operate-app", "private": true, diff --git a/frontend/service/Ethers.ts b/frontend/service/Ethers.ts index a0b4d6dbf..0ece1d23f 100644 --- a/frontend/service/Ethers.ts +++ b/frontend/service/Ethers.ts @@ -2,7 +2,7 @@ import { providers, utils } from 'ethers'; import { Contract as MulticallContract } from 'ethers-multicall'; import { PROVIDERS } from '@/constants/providers'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { Address } from '@/types/Address'; import { TransactionInfo } from '@/types/TransactionInfo'; @@ -14,7 +14,7 @@ import { TransactionInfo } from '@/types/TransactionInfo'; */ const getEthBalance = async ( address: Address, - chainId: ChainId, + chainId: EvmChainId, ): Promise<number> => { try { const provider = PROVIDERS[chainId].multicallProvider; @@ -38,7 +38,7 @@ const getEthBalance = async ( const getErc20Balance = async ( address: Address, contractAddress: Address, - chainId: ChainId, + chainId: EvmChainId, ): Promise<number> => { try { if (!contractAddress) { @@ -72,7 +72,7 @@ const getErc20Balance = async ( * @param rpc string * @returns Promise<boolean> */ -const checkRpc = async (chainId: ChainId): Promise<boolean> => { +const checkRpc = async (chainId: EvmChainId): Promise<boolean> => { const provider = PROVIDERS[chainId].provider; try { if (!provider) throw new Error('Provider is required'); @@ -96,7 +96,7 @@ const getLogsList = async ( fromBlock: number, toBlock: number, roundsLeft: number, - chainId: ChainId, + chainId: EvmChainId, ): Promise<providers.Log[]> => { const provider = PROVIDERS[chainId].provider; @@ -127,7 +127,7 @@ const getLogsList = async ( */ export const getLatestTransaction = async ( address: Address, - chainId: ChainId, + chainId: EvmChainId, ): Promise<TransactionInfo | null> => { const provider = PROVIDERS[chainId].provider; diff --git a/frontend/service/Multicall.ts b/frontend/service/Multicall.ts index 668247f9d..15f04f69a 100644 --- a/frontend/service/Multicall.ts +++ b/frontend/service/Multicall.ts @@ -4,7 +4,7 @@ import { Contract as MulticallContract, ContractCall } from 'ethers-multicall'; import { ERC20_BALANCE_OF_STRING_FRAGMENT } from '@/abis/erc20'; import { Erc20TokenConfig } from '@/config/tokens'; import { PROVIDERS } from '@/constants/providers'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { Address } from '@/types/Address'; import { AddressNumberRecord } from '@/types/Records'; @@ -16,7 +16,7 @@ import { AddressNumberRecord } from '@/types/Records'; */ const getEthBalances = async ( addresses: Address[], - chainId: ChainId, + chainId: EvmChainId, ): Promise<AddressNumberRecord | undefined> => { const provider = PROVIDERS[chainId].multicallProvider; @@ -49,7 +49,7 @@ const getEthBalances = async ( const getErc20Balances = async ( addresses: Address[], erc20TokenConfig: Erc20TokenConfig, - chainId: ChainId, + chainId: EvmChainId, ): Promise<AddressNumberRecord> => { if (!erc20TokenConfig) return {}; if (!addresses.length) return {}; diff --git a/frontend/service/Services.ts b/frontend/service/Services.ts index 9d06cbb20..72835a55e 100644 --- a/frontend/service/Services.ts +++ b/frontend/service/Services.ts @@ -1,14 +1,17 @@ import { Deployment, + MiddlewareChain, MiddlewareServiceResponse, + ServiceConfigId, ServiceHash, ServiceTemplate, } from '@/client'; import { CHAIN_CONFIG } from '@/config/chains'; import { CONTENT_TYPE_JSON_UTF8 } from '@/constants/headers'; import { BACKEND_URL_V2 } from '@/constants/urls'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; /** * Get a single service from the backend @@ -71,12 +74,13 @@ const createService = async ({ (acc, [middlewareChainKey, config]) => { acc[middlewareChainKey] = { ...config, - rpc: CHAIN_CONFIG[middlewareChainKey].rpc, + rpc: CHAIN_CONFIG[asEvmChainId(MiddlewareChain.GNOSIS)].rpc, staking_program_id: stakingProgramId, use_mech_marketplace: useMechMarketplace, }; return acc; }, + {} as (typeof serviceTemplate)['configurations'], ), }, }), @@ -96,26 +100,28 @@ const createService = async ({ const updateService = async ({ deploy, serviceTemplate, - serviceUuid, + serviceConfigId, stakingProgramId, useMechMarketplace = false, chainId, }: { deploy: boolean; serviceTemplate: ServiceTemplate; - serviceUuid: ServiceHash; + serviceConfigId: ServiceConfigId; stakingProgramId: StakingProgramId; useMechMarketplace?: boolean; - chainId: ChainId; + chainId: EvmChainId; }): Promise<MiddlewareServiceResponse> => - fetch(`${BACKEND_URL_V2}/service/${serviceUuid}`, { + fetch(`${BACKEND_URL_V2}/service/${serviceConfigId}`, { method: 'PUT', body: JSON.stringify({ ...serviceTemplate, deploy, configurations: { [CHAIN_CONFIG[chainId].middlewareChain]: { - ...serviceTemplate.configurations[CHAIN_CONFIG[chainId].middlewareChain], + ...serviceTemplate.configurations[ + CHAIN_CONFIG[chainId].middlewareChain + ], staking_program_id: stakingProgramId, rpc: CHAIN_CONFIG[chainId].rpc, use_mech_marketplace: useMechMarketplace, diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index c2edb3c2c..35fb2a8c0 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -17,7 +17,7 @@ const createEoa = async (chain: MiddlewareChain) => headers: { ...CONTENT_TYPE_JSON_UTF8, }, - body: JSON.stringify({ chain: chain }), + body: JSON.stringify({ chain }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create EOA'); @@ -29,7 +29,7 @@ const createSafe = async (chain: MiddlewareChain, owner?: string) => headers: { ...CONTENT_TYPE_JSON_UTF8, }, - body: JSON.stringify({ chain: chain, owner: owner }), + body: JSON.stringify({ chain, owner }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create safe'); @@ -41,7 +41,7 @@ const addBackupOwner = async (chain: MiddlewareChain, owner: string) => headers: { ...CONTENT_TYPE_JSON_UTF8, }, - body: JSON.stringify({ chain: chain, owner: owner }), + body: JSON.stringify({ chain, owner }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to add backup owner'); diff --git a/frontend/service/agents/PredictTrader.ts b/frontend/service/agents/PredictTrader.ts index c16141dd1..7ebca82b9 100644 --- a/frontend/service/agents/PredictTrader.ts +++ b/frontend/service/agents/PredictTrader.ts @@ -3,7 +3,7 @@ import { formatEther } from 'ethers/lib/utils'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { PROVIDERS } from '@/constants/providers'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; import { StakingContractDetails, StakingRewardsInfo } from '@/types/Autonolas'; @@ -18,18 +18,18 @@ export abstract class PredictTraderService extends StakedAgentService { agentMultisigAddress, serviceId, stakingProgramId, - chainId = ChainId.Gnosis, + chainId = EvmChainId.Gnosis, }: { agentMultisigAddress: Address; serviceId: number; stakingProgramId: StakingProgramId; - chainId?: ChainId; + chainId?: EvmChainId; }): Promise<StakingRewardsInfo | undefined> => { if (!agentMultisigAddress) return; if (!serviceId) return; const stakingProgramConfig = - STAKING_PROGRAMS[ChainId.Gnosis][stakingProgramId]; + STAKING_PROGRAMS[EvmChainId.Gnosis][stakingProgramId]; if (!stakingProgramConfig) throw new Error('Staking program not found'); @@ -119,7 +119,7 @@ export abstract class PredictTraderService extends StakedAgentService { static getAvailableRewardsForEpoch = async ( stakingProgramId: StakingProgramId, - chainId: ChainId = ChainId.Gnosis, + chainId: EvmChainId = EvmChainId.Gnosis, ): Promise<number | undefined> => { const { contract: stakingTokenProxy } = STAKING_PROGRAMS[chainId][stakingProgramId]; @@ -142,11 +142,11 @@ export abstract class PredictTraderService extends StakedAgentService { }; static getStakingContractDetailsByServiceIdStakingProgram = async ( - serviceId: number, + serviceNftTokenId: number, stakingProgramId: StakingProgramId, - chainId: ChainId = ChainId.Gnosis, + chainId: EvmChainId = EvmChainId.Gnosis, ): Promise<Partial<Maybe<StakingContractDetails>>> => { - if (!serviceId) return null; + if (!serviceNftTokenId) return null; const { multicallProvider } = PROVIDERS[chainId]; @@ -158,8 +158,8 @@ export abstract class PredictTraderService extends StakedAgentService { stakingTokenProxy.maxNumServices(), stakingTokenProxy.getServiceIds(), stakingTokenProxy.minStakingDuration(), - stakingTokenProxy.getServiceInfo(serviceId), - stakingTokenProxy.getStakingState(serviceId), + stakingTokenProxy.getServiceInfo(serviceNftTokenId), + stakingTokenProxy.getStakingState(serviceNftTokenId), stakingTokenProxy.minStakingDeposit(), ]; @@ -200,7 +200,7 @@ export abstract class PredictTraderService extends StakedAgentService { */ static getStakingContractDetailsByName = async ( stakingProgramId: StakingProgramId, - chainId: ChainId, + chainId: EvmChainId, ): Promise<Partial<StakingContractDetails>> => { const provider = PROVIDERS[chainId].multicallProvider; diff --git a/frontend/service/agents/StakedAgentService.ts b/frontend/service/agents/StakedAgentService.ts index 442c63c84..790cef882 100644 --- a/frontend/service/agents/StakedAgentService.ts +++ b/frontend/service/agents/StakedAgentService.ts @@ -16,7 +16,7 @@ import { STAKING_PROGRAMS, } from '@/config/stakingPrograms'; import { PROVIDERS } from '@/constants/providers'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { ContractType } from '@/enums/Contract'; import { ServiceRegistryL2ServiceState } from '@/enums/ServiceRegistryL2ServiceState'; import { StakingProgramId } from '@/enums/StakingProgram'; @@ -44,26 +44,26 @@ export abstract class StakedAgentService { agentMultisigAddress: Address, serviceId: number, stakingProgramId: StakingProgramId, - chainId: ChainId, + chainId: EvmChainId, ): Promise<unknown>; abstract getAvailableRewardsForEpoch( stakingProgramId: StakingProgramId, - chainId: ChainId, + chainId: EvmChainId, ): Promise<unknown>; abstract getStakingContractDetailsByServiceIdStakingProgram( serviceId: number, stakingProgramId: StakingProgramId, - chainId: ChainId, + chainId: EvmChainId, ): Promise<unknown>; abstract getStakingContractDetailsByName( stakingProgramId: StakingProgramId, - chainId: ChainId, + chainId: EvmChainId, ): Promise<unknown>; abstract getInstance(): StakedAgentService; static getCurrentStakingProgramByServiceId = async ( serviceId: number, - chainId: ChainId, + chainId: EvmChainId, ): Promise<Maybe<StakingProgramId>> => { try { const { multicallProvider } = PROVIDERS[chainId]; @@ -114,7 +114,7 @@ export abstract class StakedAgentService { static getServiceRegistryInfo = async ( address: Address, // generally masterSafeAddress serviceId: number, - chainId: ChainId, + chainId: EvmChainId, ): Promise<GetServiceRegistryInfoResponse> => { if (!OLAS_CONTRACTS[chainId]) { throw new Error('Chain not supported'); @@ -160,7 +160,7 @@ export abstract class StakedAgentService { * @example getStakingProgramIdByAddress('0x3052451e1eAee78e62E169AfdF6288F8791F2918') // StakingProgramId.Beta4 */ static getStakingProgramIdByAddress = ( - chainId: number | ChainId, + chainId: number | EvmChainId, contractAddress: Address, ): Nullable<StakingProgramId> => { const addresses = STAKING_PROGRAM_ADDRESS[chainId]; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index ca51cb094..d13230b55 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "baseUrl": ".", "target": "ES2015", "allowJs": true, "esModuleInterop": true, diff --git a/frontend/types/Agent.ts b/frontend/types/Agent.ts index 4f95eb552..db7079a2b 100644 --- a/frontend/types/Agent.ts +++ b/frontend/types/Agent.ts @@ -1,12 +1,14 @@ -import { ChainId } from '@/enums/Chain'; +import { MiddlewareChain } from '@/client'; +import { EvmChainId } from '@/enums/Chain'; import { PredictTraderService } from '@/service/agents/PredictTrader'; export type StakedAgentServiceInstance = PredictTraderService; export type AgentConfig = { name: string; - homeChainId: ChainId; - requiresAgentSafesOn: ChainId[]; + evmHomeChainId: EvmChainId; + middlewareHomeChainId: MiddlewareChain; + requiresAgentSafesOn: EvmChainId[]; agentSafeFundingRequirements: Record<string, number>; - requiresMasterSafesOn: ChainId[]; + requiresMasterSafesOn: EvmChainId[]; serviceApi: typeof PredictTraderService; }; diff --git a/frontend/utils/middlewareHelpers.ts b/frontend/utils/middlewareHelpers.ts index cd32c1aaf..100334721 100644 --- a/frontend/utils/middlewareHelpers.ts +++ b/frontend/utils/middlewareHelpers.ts @@ -1,5 +1,5 @@ import { MiddlewareChain } from '@/client'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; /** * Converts middleware chain enums to chain ids @@ -7,31 +7,29 @@ import { ChainId } from '@/enums/Chain'; * @returns ChainId * @throws Error */ -export const convertMiddlewareChainToChainId = ( - chain: MiddlewareChain | string, -): ChainId => { +export const asEvmChainId = (chain?: MiddlewareChain | string): EvmChainId => { switch (chain) { case MiddlewareChain.ETHEREUM: - return ChainId.Ethereum; + return EvmChainId.Ethereum; case MiddlewareChain.OPTIMISM: - return ChainId.Optimism; + return EvmChainId.Optimism; case MiddlewareChain.GNOSIS: - return ChainId.Gnosis; + return EvmChainId.Gnosis; case MiddlewareChain.BASE: - return ChainId.Base; + return EvmChainId.Base; } throw new Error(`Invalid middleware chain enum: ${chain}`); }; -export const convertChainIdToMiddlewareChain = (chainId: ChainId | number) => { +export const asMiddlewareChain = (chainId?: EvmChainId | number) => { switch (chainId) { - case ChainId.Ethereum: + case EvmChainId.Ethereum: return MiddlewareChain.ETHEREUM; - case ChainId.Optimism: + case EvmChainId.Optimism: return MiddlewareChain.OPTIMISM; - case ChainId.Gnosis: + case EvmChainId.Gnosis: return MiddlewareChain.GNOSIS; - case ChainId.Base: + case EvmChainId.Base: return MiddlewareChain.BASE; } throw new Error(`Invalid chain id: ${chainId}`); diff --git a/frontend/utils/setupMulticall.ts b/frontend/utils/setupMulticall.ts index e9bccc481..95a282d0f 100644 --- a/frontend/utils/setupMulticall.ts +++ b/frontend/utils/setupMulticall.ts @@ -1,19 +1,19 @@ import { setMulticallAddress } from 'ethers-multicall'; -import { ChainId } from '@/enums/Chain'; +import { EvmChainId } from '@/enums/Chain'; import { Address } from '@/types/Address'; const DEFAULT_MULTICALL_ADDRESS = '0xcA11bde05977b3631167028862bE2a173976CA11'; type AddressesForAllChainIds = { - [chainId in ChainId]: Address; + [chainId in EvmChainId]: Address; }; const addresses: AddressesForAllChainIds = { - [ChainId.Ethereum]: DEFAULT_MULTICALL_ADDRESS, - [ChainId.Base]: DEFAULT_MULTICALL_ADDRESS, - [ChainId.Gnosis]: DEFAULT_MULTICALL_ADDRESS, - [ChainId.Optimism]: DEFAULT_MULTICALL_ADDRESS, + [EvmChainId.Ethereum]: DEFAULT_MULTICALL_ADDRESS, + [EvmChainId.Base]: DEFAULT_MULTICALL_ADDRESS, + [EvmChainId.Gnosis]: DEFAULT_MULTICALL_ADDRESS, + [EvmChainId.Optimism]: DEFAULT_MULTICALL_ADDRESS, }; /** @@ -25,6 +25,6 @@ export const setupMulticallAddresses = async () => { if (!address) { throw new Error(`Multicall address not set for chainId: ${chainId}`); } - setMulticallAddress(+chainId as ChainId, address); + setMulticallAddress(+chainId as EvmChainId, address); }); }; diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 5f4411fc4..ed10fce83 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -4,12 +4,12 @@ "@adobe/css-tools@^4.3.2": version "4.3.3" - resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.3.3.tgz#90749bde8b89cd41764224f5aac29cd4138f75ff" + resolved "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz" integrity sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ== "@ampproject/remapping@^2.2.0": version "2.3.0" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: "@jridgewell/gen-mapping" "^0.3.5" @@ -17,14 +17,14 @@ "@ant-design/colors@^7.0.0", "@ant-design/colors@^7.0.2": version "7.0.2" - resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-7.0.2.tgz#c5c753a467ce8d86ba7ca4736d2c01f599bb5492" + resolved "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.2.tgz" integrity sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg== dependencies: "@ctrl/tinycolor" "^3.6.1" "@ant-design/cssinjs@^1.18.4", "@ant-design/cssinjs@^1.19.1": version "1.20.0" - resolved "https://registry.yarnpkg.com/@ant-design/cssinjs/-/cssinjs-1.20.0.tgz#878bc6c5b08f73db76da54c347a7ebb3fa4858bb" + resolved "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.20.0.tgz" integrity sha512-uG3iWzJxgNkADdZmc6W0Ci3iQAUOvLMcM8SnnmWq3r6JeocACft4ChnY/YWvI2Y+rG/68QBla/O+udke1yH3vg== dependencies: "@babel/runtime" "^7.11.1" @@ -37,12 +37,12 @@ "@ant-design/icons-svg@^4.4.0": version "4.4.2" - resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz#ed2be7fb4d82ac7e1d45a54a5b06d6cecf8be6f6" + resolved "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz" integrity sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA== "@ant-design/icons@^5.3.0", "@ant-design/icons@^5.3.7": version "5.3.7" - resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-5.3.7.tgz#d9f3654bf7934ee5faba43f91b5a187f5309ec68" + resolved "https://registry.npmjs.org/@ant-design/icons/-/icons-5.3.7.tgz" integrity sha512-bCPXTAg66f5bdccM4TT21SQBDO1Ek2gho9h3nO9DAKXJP4sq+5VBjrQMSxMVXSB3HyEz+cUbHQ5+6ogxCOpaew== dependencies: "@ant-design/colors" "^7.0.0" @@ -53,7 +53,7 @@ "@ant-design/react-slick@~1.1.2": version "1.1.2" - resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-1.1.2.tgz#f84ce3e4d0dc941f02b16f1d1d6d7a371ffbb4f1" + resolved "https://registry.npmjs.org/@ant-design/react-slick/-/react-slick-1.1.2.tgz" integrity sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA== dependencies: "@babel/runtime" "^7.10.4" @@ -64,7 +64,7 @@ "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== dependencies: "@babel/highlight" "^7.24.2" @@ -72,12 +72,12 @@ "@babel/compat-data@^7.23.5": version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz" integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.5.tgz#15ab5b98e101972d171aeef92ac70d8d6718f06a" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz" integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== dependencies: "@ampproject/remapping" "^2.2.0" @@ -98,7 +98,7 @@ "@babel/generator@^7.24.5", "@babel/generator@^7.7.2": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.5.tgz#e5afc068f932f05616b66713e28d0f04e99daeb3" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz" integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== dependencies: "@babel/types" "^7.24.5" @@ -108,7 +108,7 @@ "@babel/helper-compilation-targets@^7.23.6": version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz" integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== dependencies: "@babel/compat-data" "^7.23.5" @@ -119,12 +119,12 @@ "@babel/helper-environment-visitor@^7.22.20": version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== "@babel/helper-function-name@^7.23.0": version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: "@babel/template" "^7.22.15" @@ -132,21 +132,21 @@ "@babel/helper-hoist-variables@^7.22.5": version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== dependencies: "@babel/types" "^7.22.5" "@babel/helper-module-imports@^7.24.3": version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz" integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== dependencies: "@babel/types" "^7.24.0" "@babel/helper-module-transforms@^7.24.5": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz#ea6c5e33f7b262a0ae762fd5986355c45f54a545" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz" integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== dependencies: "@babel/helper-environment-visitor" "^7.22.20" @@ -157,41 +157,41 @@ "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz#a924607dd254a65695e5bd209b98b902b3b2f11a" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz" integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== "@babel/helper-simple-access@^7.24.5": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz#50da5b72f58c16b07fbd992810be6049478e85ba" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz" integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== dependencies: "@babel/types" "^7.24.5" "@babel/helper-split-export-declaration@^7.24.5": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz#b9a67f06a46b0b339323617c8c6213b9055a78b6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz" integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== dependencies: "@babel/types" "^7.24.5" "@babel/helper-string-parser@^7.24.1": version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz" integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== "@babel/helper-validator-identifier@^7.24.5": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz#918b1a7fa23056603506370089bd990d8720db62" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz" integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== "@babel/helper-validator-option@^7.23.5": version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== "@babel/helpers@^7.24.5": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.5.tgz#fedeb87eeafa62b621160402181ad8585a22a40a" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz" integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== dependencies: "@babel/template" "^7.24.0" @@ -200,7 +200,7 @@ "@babel/highlight@^7.24.2": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.5.tgz#bc0613f98e1dd0720e99b2a9ee3760194a704b6e" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz" integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== dependencies: "@babel/helper-validator-identifier" "^7.24.5" @@ -210,117 +210,117 @@ "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.5.tgz#4a4d5ab4315579e5398a82dcf636ca80c3392790" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz" integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: "@babel/helper-plugin-utils" "^7.12.13" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.7.2": version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz" integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== dependencies: "@babel/helper-plugin-utils" "^7.24.0" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== dependencies: "@babel/helper-plugin-utils" "^7.10.4" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-top-level-await@^7.8.3": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.7.2": version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz" integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== dependencies: "@babel/helper-plugin-utils" "^7.24.0" "@babel/runtime@^7.10.1", "@babel/runtime@^7.10.4", "@babel/runtime@^7.11.1", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.7", "@babel/runtime@^7.18.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.0", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.5", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.6", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.4", "@babel/runtime@^7.24.5", "@babel/runtime@^7.9.2": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.5.tgz" integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== dependencies: regenerator-runtime "^0.14.0" "@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== dependencies: "@babel/code-frame" "^7.23.5" @@ -329,7 +329,7 @@ "@babel/traverse@^7.24.5": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.5.tgz#972aa0bc45f16983bf64aa1f877b2dd0eea7e6f8" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz" integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== dependencies: "@babel/code-frame" "^7.24.2" @@ -345,7 +345,7 @@ "@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3": version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.5.tgz#7661930afc638a5383eb0c4aee59b74f38db84d7" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz" integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== dependencies: "@babel/helper-string-parser" "^7.24.1" @@ -354,63 +354,63 @@ "@bcoe/v8-coverage@^0.2.3": version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== "@cspotcode/source-map-support@^0.8.0": version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== dependencies: "@jridgewell/trace-mapping" "0.3.9" "@ctrl/tinycolor@^3.6.1": version "3.6.1" - resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz#b6c75a56a1947cc916ea058772d666a2c8932f31" + resolved "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz" integrity sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA== "@emotion/hash@^0.8.0": version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz" integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== "@emotion/is-prop-valid@1.2.2": version "1.2.2" - resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337" + resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz" integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw== dependencies: "@emotion/memoize" "^0.8.1" "@emotion/memoize@^0.8.1": version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17" + resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz" integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA== "@emotion/unitless@0.8.1": version "0.8.1" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3" + resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz" integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ== "@emotion/unitless@^0.7.5": version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz" integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== dependencies: eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": version "4.10.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz" integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== "@eslint/eslintrc@^2.1.4": version "2.1.4" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz" integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" @@ -425,12 +425,12 @@ "@eslint/js@8.57.0": version "8.57.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + resolved "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz" integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== "@ethersproject/abi@5.7.0", "@ethersproject/abi@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz" integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== dependencies: "@ethersproject/address" "^5.7.0" @@ -445,7 +445,7 @@ "@ethersproject/abstract-provider@5.7.0", "@ethersproject/abstract-provider@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz" integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== dependencies: "@ethersproject/bignumber" "^5.7.0" @@ -458,7 +458,7 @@ "@ethersproject/abstract-signer@5.7.0", "@ethersproject/abstract-signer@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz" integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== dependencies: "@ethersproject/abstract-provider" "^5.7.0" @@ -469,7 +469,7 @@ "@ethersproject/address@5.7.0", "@ethersproject/address@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz" integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== dependencies: "@ethersproject/bignumber" "^5.7.0" @@ -480,14 +480,14 @@ "@ethersproject/base64@5.7.0", "@ethersproject/base64@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz" integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== dependencies: "@ethersproject/bytes" "^5.7.0" "@ethersproject/basex@5.7.0", "@ethersproject/basex@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/basex/-/basex-5.7.0.tgz#97034dc7e8938a8ca943ab20f8a5e492ece4020b" + resolved "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz" integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -495,7 +495,7 @@ "@ethersproject/bignumber@5.7.0", "@ethersproject/bignumber@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz" integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -504,21 +504,21 @@ "@ethersproject/bytes@5.7.0", "@ethersproject/bytes@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz" integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== dependencies: "@ethersproject/logger" "^5.7.0" "@ethersproject/constants@5.7.0", "@ethersproject/constants@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz" integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== dependencies: "@ethersproject/bignumber" "^5.7.0" "@ethersproject/contracts@5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/contracts/-/contracts-5.7.0.tgz#c305e775abd07e48aa590e1a877ed5c316f8bd1e" + resolved "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz" integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== dependencies: "@ethersproject/abi" "^5.7.0" @@ -534,7 +534,7 @@ "@ethersproject/hash@5.7.0", "@ethersproject/hash@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz" integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== dependencies: "@ethersproject/abstract-signer" "^5.7.0" @@ -549,7 +549,7 @@ "@ethersproject/hdnode@5.7.0", "@ethersproject/hdnode@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hdnode/-/hdnode-5.7.0.tgz#e627ddc6b466bc77aebf1a6b9e47405ca5aef9cf" + resolved "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz" integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== dependencies: "@ethersproject/abstract-signer" "^5.7.0" @@ -567,7 +567,7 @@ "@ethersproject/json-wallets@5.7.0", "@ethersproject/json-wallets@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz#5e3355287b548c32b368d91014919ebebddd5360" + resolved "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz" integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== dependencies: "@ethersproject/abstract-signer" "^5.7.0" @@ -586,7 +586,7 @@ "@ethersproject/keccak256@5.7.0", "@ethersproject/keccak256@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz" integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -594,19 +594,19 @@ "@ethersproject/logger@5.7.0", "@ethersproject/logger@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz" integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== "@ethersproject/networks@5.7.1", "@ethersproject/networks@^5.7.0": version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz" integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== dependencies: "@ethersproject/logger" "^5.7.0" "@ethersproject/pbkdf2@5.7.0", "@ethersproject/pbkdf2@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz#d2267d0a1f6e123f3771007338c47cccd83d3102" + resolved "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz" integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -614,14 +614,14 @@ "@ethersproject/properties@5.7.0", "@ethersproject/properties@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz" integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== dependencies: "@ethersproject/logger" "^5.7.0" "@ethersproject/providers@5.7.2": version "5.7.2" - resolved "https://registry.yarnpkg.com/@ethersproject/providers/-/providers-5.7.2.tgz#f8b1a4f275d7ce58cf0a2eec222269a08beb18cb" + resolved "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz" integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== dependencies: "@ethersproject/abstract-provider" "^5.7.0" @@ -647,7 +647,7 @@ "@ethersproject/random@5.7.0", "@ethersproject/random@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/random/-/random-5.7.0.tgz#af19dcbc2484aae078bb03656ec05df66253280c" + resolved "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz" integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -655,7 +655,7 @@ "@ethersproject/rlp@5.7.0", "@ethersproject/rlp@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz" integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -663,7 +663,7 @@ "@ethersproject/sha2@5.7.0", "@ethersproject/sha2@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.7.0.tgz#9a5f7a7824ef784f7f7680984e593a800480c9fb" + resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz" integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -672,7 +672,7 @@ "@ethersproject/signing-key@5.7.0", "@ethersproject/signing-key@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz" integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -684,7 +684,7 @@ "@ethersproject/solidity@5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/solidity/-/solidity-5.7.0.tgz#5e9c911d8a2acce2a5ebb48a5e2e0af20b631cb8" + resolved "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz" integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== dependencies: "@ethersproject/bignumber" "^5.7.0" @@ -696,7 +696,7 @@ "@ethersproject/strings@5.7.0", "@ethersproject/strings@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz" integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -705,7 +705,7 @@ "@ethersproject/transactions@5.7.0", "@ethersproject/transactions@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz" integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== dependencies: "@ethersproject/address" "^5.7.0" @@ -720,7 +720,7 @@ "@ethersproject/units@5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/units/-/units-5.7.0.tgz#637b563d7e14f42deeee39245275d477aae1d8b1" + resolved "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz" integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== dependencies: "@ethersproject/bignumber" "^5.7.0" @@ -729,7 +729,7 @@ "@ethersproject/wallet@5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wallet/-/wallet-5.7.0.tgz#4e5d0790d96fe21d61d38fb40324e6c7ef350b2d" + resolved "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz" integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== dependencies: "@ethersproject/abstract-provider" "^5.7.0" @@ -750,7 +750,7 @@ "@ethersproject/web@5.7.1", "@ethersproject/web@^5.7.0": version "5.7.1" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz" integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== dependencies: "@ethersproject/base64" "^5.7.0" @@ -761,7 +761,7 @@ "@ethersproject/wordlists@5.7.0", "@ethersproject/wordlists@^5.7.0": version "5.7.0" - resolved "https://registry.yarnpkg.com/@ethersproject/wordlists/-/wordlists-5.7.0.tgz#8fb2c07185d68c3e09eb3bfd6e779ba2774627f5" + resolved "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz" integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== dependencies: "@ethersproject/bytes" "^5.7.0" @@ -772,17 +772,17 @@ "@fontsource/inter@^5.0.17": version "5.0.18" - resolved "https://registry.yarnpkg.com/@fontsource/inter/-/inter-5.0.18.tgz#eaddac790ee74b70932030f37ebaa9fc76decbd8" + resolved "https://registry.npmjs.org/@fontsource/inter/-/inter-5.0.18.tgz" integrity sha512-YCsoYPTcs713sI7tLtxaPrIhXAXvEetGg5Ry02ivA8qUOb3fQHojbK/X9HLD5OOKvFUNR2Ynkwb1kR1hVKQHpw== "@graphql-typed-document-node/core@^3.2.0": version "3.2.0" - resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861" + resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz" integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== "@humanwhocodes/config-array@^0.11.14": version "0.11.14" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz" integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== dependencies: "@humanwhocodes/object-schema" "^2.0.2" @@ -791,17 +791,17 @@ "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== "@humanwhocodes/object-schema@^2.0.2": version "2.0.3" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== "@isaacs/cliui@^8.0.2": version "8.0.2" - resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== dependencies: string-width "^5.1.2" @@ -813,7 +813,7 @@ "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" @@ -824,12 +824,12 @@ "@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== "@jest/console@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz" integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: "@jest/types" "^29.6.3" @@ -841,7 +841,7 @@ "@jest/core@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz" integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: "@jest/console" "^29.7.0" @@ -875,7 +875,7 @@ "@jest/environment@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: "@jest/fake-timers" "^29.7.0" @@ -885,14 +885,14 @@ "@jest/expect-utils@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== dependencies: jest-get-type "^29.6.3" "@jest/expect@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz" integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: expect "^29.7.0" @@ -900,7 +900,7 @@ "@jest/fake-timers@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: "@jest/types" "^29.6.3" @@ -912,7 +912,7 @@ "@jest/globals@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: "@jest/environment" "^29.7.0" @@ -922,7 +922,7 @@ "@jest/reporters@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz" integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" @@ -952,14 +952,14 @@ "@jest/schemas@^29.6.3": version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: "@sinclair/typebox" "^0.27.8" "@jest/source-map@^29.6.3": version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz" integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: "@jridgewell/trace-mapping" "^0.3.18" @@ -968,7 +968,7 @@ "@jest/test-result@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz" integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: "@jest/console" "^29.7.0" @@ -978,7 +978,7 @@ "@jest/test-sequencer@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz" integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: "@jest/test-result" "^29.7.0" @@ -988,7 +988,7 @@ "@jest/transform@^29.7.0": version "29.7.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz" integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: "@babel/core" "^7.11.6" @@ -1009,7 +1009,7 @@ "@jest/types@^29.6.3": version "29.6.3" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: "@jest/schemas" "^29.6.3" @@ -1021,7 +1021,7 @@ "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== dependencies: "@jridgewell/set-array" "^1.2.1" @@ -1030,22 +1030,22 @@ "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/set-array@^1.2.1": version "1.2.1" - resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== dependencies: "@jridgewell/resolve-uri" "^3.0.3" @@ -1053,7 +1053,7 @@ "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: "@jridgewell/resolve-uri" "^3.1.0" @@ -1061,64 +1061,64 @@ "@next/env@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.3.tgz#d6def29d1c763c0afb397343a15a82e7d92353a0" + resolved "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz" integrity sha512-W7fd7IbkfmeeY2gXrzJYDx8D2lWKbVoTIj1o1ScPHNzvp30s1AuoEFSdr39bC5sjxJaxTtq3OTCZboNp0lNWHA== "@next/eslint-plugin-next@14.1.0": version "14.1.0" - resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.0.tgz#29b041233fac7417e22eefa4146432d5cd910820" + resolved "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.0.tgz" integrity sha512-x4FavbNEeXx/baD/zC/SdrvkjSby8nBn8KcCREqk6UuwvwoAPZmaV8TFCAuo/cpovBRTIY67mHhe86MQQm/68Q== dependencies: glob "10.3.10" "@next/swc-darwin-arm64@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.3.tgz#db1a05eb88c0224089b815ad10ac128ec79c2cdb" + resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.3.tgz#db1a05eb88c0224089b815ad10ac128ec79c2cdb" integrity sha512-3pEYo/RaGqPP0YzwnlmPN2puaF2WMLM3apt5jLW2fFdXD9+pqcoTzRk+iZsf8ta7+quAe4Q6Ms0nR0SFGFdS1A== "@next/swc-darwin-x64@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz#a3f8af05b5f9a52ac3082e66ac29e125ab1d7b9c" + resolved "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.3.tgz#a3f8af05b5f9a52ac3082e66ac29e125ab1d7b9c" integrity sha512-6adp7waE6P1TYFSXpY366xwsOnEXM+y1kgRpjSRVI2CBDOcbRjsJ67Z6EgKIqWIue52d2q/Mx8g9MszARj8IEA== "@next/swc-linux-arm64-gnu@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz#4e63f43879285b52554bfd39e6e0cc78a9b27bbf" + resolved "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.3.tgz#4e63f43879285b52554bfd39e6e0cc78a9b27bbf" integrity sha512-cuzCE/1G0ZSnTAHJPUT1rPgQx1w5tzSX7POXSLaS7w2nIUJUD+e25QoXD/hMfxbsT9rslEXugWypJMILBj/QsA== "@next/swc-linux-arm64-musl@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz#ebdaed26214448b1e6f2c3e8b3cd29bfba387990" + resolved "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.3.tgz#ebdaed26214448b1e6f2c3e8b3cd29bfba387990" integrity sha512-0D4/oMM2Y9Ta3nGuCcQN8jjJjmDPYpHX9OJzqk42NZGJocU2MqhBq5tWkJrUQOQY9N+In9xOdymzapM09GeiZw== "@next/swc-linux-x64-gnu@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz#19e3bcc137c3b582a1ab867106817e5c90a20593" + resolved "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.3.tgz" integrity sha512-ENPiNnBNDInBLyUU5ii8PMQh+4XLr4pG51tOp6aJ9xqFQ2iRI6IH0Ds2yJkAzNV1CfyagcyzPfROMViS2wOZ9w== "@next/swc-linux-x64-musl@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz#794a539b98e064169cf0ff7741b2a4fb16adec7d" + resolved "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.3.tgz" integrity sha512-BTAbq0LnCbF5MtoM7I/9UeUu/8ZBY0i8SFjUMCbPDOLv+un67e2JgyN4pmgfXBwy/I+RHu8q+k+MCkDN6P9ViQ== "@next/swc-win32-arm64-msvc@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz#eda9fa0fbf1ff9113e87ac2668ee67ce9e5add5a" + resolved "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.3.tgz#eda9fa0fbf1ff9113e87ac2668ee67ce9e5add5a" integrity sha512-AEHIw/dhAMLNFJFJIJIyOFDzrzI5bAjI9J26gbO5xhAKHYTZ9Or04BesFPXiAYXDNdrwTP2dQceYA4dL1geu8A== "@next/swc-win32-ia32-msvc@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz#7c1190e3f640ab16580c6bdbd7d0e766b9920457" + resolved "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.3.tgz#7c1190e3f640ab16580c6bdbd7d0e766b9920457" integrity sha512-vga40n1q6aYb0CLrM+eEmisfKCR45ixQYXuBXxOOmmoV8sYST9k7E3US32FsY+CkkF7NtzdcebiFT4CHuMSyZw== "@next/swc-win32-x64-msvc@14.2.3": version "14.2.3" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz#2be4e39ee25bfbd85be78eea17c0e7751dc4323c" + resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.3.tgz#2be4e39ee25bfbd85be78eea17c0e7751dc4323c" integrity sha512-Q1/zm43RWynxrO7lW4ehciQVj+5ePBhOK+/K2P7pLFX3JaJ/IZVC69SHidrmZSOkqz7ECIOhhy7XhAFG4JYyHA== "@nodelib/fs.scandir@2.1.5": version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: "@nodelib/fs.stat" "2.0.5" @@ -1126,12 +1126,12 @@ "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: "@nodelib/fs.scandir" "2.1.5" @@ -1139,24 +1139,24 @@ "@pkgjs/parseargs@^0.11.0": version "0.11.0" - resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== "@pkgr/core@^0.1.0": version "0.1.1" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + resolved "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz" integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== "@rc-component/async-validator@^5.0.3": version "5.0.4" - resolved "https://registry.yarnpkg.com/@rc-component/async-validator/-/async-validator-5.0.4.tgz#5291ad92f00a14b6766fc81735c234277f83e948" + resolved "https://registry.npmjs.org/@rc-component/async-validator/-/async-validator-5.0.4.tgz" integrity sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg== dependencies: "@babel/runtime" "^7.24.4" "@rc-component/color-picker@~1.5.3": version "1.5.3" - resolved "https://registry.yarnpkg.com/@rc-component/color-picker/-/color-picker-1.5.3.tgz#f3b0e14bb67ec5ee77d1fd5d261f63dd4fd00449" + resolved "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-1.5.3.tgz" integrity sha512-+tGGH3nLmYXTalVe0L8hSZNs73VTP5ueSHwUlDC77KKRaN7G4DS4wcpG5DTDzdcV/Yas+rzA6UGgIyzd8fS4cw== dependencies: "@babel/runtime" "^7.23.6" @@ -1166,7 +1166,7 @@ "@rc-component/context@^1.4.0": version "1.4.0" - resolved "https://registry.yarnpkg.com/@rc-component/context/-/context-1.4.0.tgz#dc6fb021d6773546af8f016ae4ce9aea088395e8" + resolved "https://registry.npmjs.org/@rc-component/context/-/context-1.4.0.tgz" integrity sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w== dependencies: "@babel/runtime" "^7.10.1" @@ -1174,14 +1174,14 @@ "@rc-component/mini-decimal@^1.0.1": version "1.1.0" - resolved "https://registry.yarnpkg.com/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz#7b7a362b14a0a54cb5bc6fd2b82731f29f11d9b0" + resolved "https://registry.npmjs.org/@rc-component/mini-decimal/-/mini-decimal-1.1.0.tgz" integrity sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ== dependencies: "@babel/runtime" "^7.18.0" "@rc-component/mutate-observer@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz#ee53cc88b78aade3cd0653609215a44779386fd8" + resolved "https://registry.npmjs.org/@rc-component/mutate-observer/-/mutate-observer-1.1.0.tgz" integrity sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw== dependencies: "@babel/runtime" "^7.18.0" @@ -1190,7 +1190,7 @@ "@rc-component/portal@^1.0.0-8", "@rc-component/portal@^1.0.0-9", "@rc-component/portal@^1.0.2", "@rc-component/portal@^1.1.0", "@rc-component/portal@^1.1.1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@rc-component/portal/-/portal-1.1.2.tgz#55db1e51d784e034442e9700536faaa6ab63fc71" + resolved "https://registry.npmjs.org/@rc-component/portal/-/portal-1.1.2.tgz" integrity sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg== dependencies: "@babel/runtime" "^7.18.0" @@ -1199,7 +1199,7 @@ "@rc-component/tour@~1.15.0": version "1.15.0" - resolved "https://registry.yarnpkg.com/@rc-component/tour/-/tour-1.15.0.tgz#37a66ae5af8eefaf0ab0e22ddd8e6fecdbdc14a7" + resolved "https://registry.npmjs.org/@rc-component/tour/-/tour-1.15.0.tgz" integrity sha512-h6hyILDwL+In9GAgRobwRWihLqqsD7Uft3fZGrJ7L4EiyCoxbnNYwzPXDfz7vNDhWeVyvAWQJj9fJCzpI4+b4g== dependencies: "@babel/runtime" "^7.18.0" @@ -1210,7 +1210,7 @@ "@rc-component/trigger@^2.0.0", "@rc-component/trigger@^2.1.1": version "2.1.1" - resolved "https://registry.yarnpkg.com/@rc-component/trigger/-/trigger-2.1.1.tgz#47973f1156ba63810c913eb46cbaedeba913874b" + resolved "https://registry.npmjs.org/@rc-component/trigger/-/trigger-2.1.1.tgz" integrity sha512-UjHkedkgtEcgQu87w1VuWug1idoDJV7VUt0swxHXRcmei2uu1AuUzGBPEUlmOmXGJ+YtTgZfVLi7kuAUKoZTMA== dependencies: "@babel/runtime" "^7.23.2" @@ -1222,36 +1222,36 @@ "@rushstack/eslint-patch@^1.3.3": version "1.10.3" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz#391d528054f758f81e53210f1a1eebcf1a8b1d20" + resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz" integrity sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg== "@sinclair/typebox@^0.27.8": version "0.27.8" - resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== "@sinonjs/commons@^3.0.0": version "3.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz" integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" "@sinonjs/fake-timers@^10.0.2": version "10.3.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: "@sinonjs/commons" "^3.0.0" "@swc/counter@^0.1.3": version "0.1.3" - resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + resolved "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz" integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== "@swc/helpers@0.5.5": version "0.5.5" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.5.tgz#12689df71bfc9b21c4f4ca00ae55f2f16c8b77c0" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz" integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A== dependencies: "@swc/counter" "^0.1.3" @@ -1259,19 +1259,19 @@ "@tanstack/query-core@5.56.2": version "5.56.2" - resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.56.2.tgz#2def2fb0290cd2836bbb08afb0c175595bb8109b" + resolved "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.56.2.tgz" integrity sha512-gor0RI3/R5rVV3gXfddh1MM+hgl0Z4G7tj6Xxpq6p2I03NGPaJ8dITY9Gz05zYYb/EJq9vPas/T4wn9EaDPd4Q== "@tanstack/react-query@^5.29.0": version "5.56.2" - resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.56.2.tgz#3a0241b9d010910905382f5e99160997b8795f91" + resolved "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.56.2.tgz" integrity sha512-SR0GzHVo6yzhN72pnRhkEFRAHMsUo5ZPzAxfTMvUxFIDVS6W9LYUp6nXW3fcHVdg0ZJl8opSH85jqahvm6DSVg== dependencies: "@tanstack/query-core" "5.56.2" "@testing-library/dom@^9.0.0": version "9.3.4" - resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-9.3.4.tgz#50696ec28376926fec0a1bf87d9dbac5e27f60ce" + resolved "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.4.tgz" integrity sha512-FlS4ZWlp97iiNWig0Muq8p+3rVDjRiYE+YKGbAqXOu9nwJFFOdL00kFpz42M+4huzYi86vAK1sOOfyOG45muIQ== dependencies: "@babel/code-frame" "^7.10.4" @@ -1285,7 +1285,7 @@ "@testing-library/jest-dom@^6.4.2": version "6.4.5" - resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz#badb40296477149136dabef32b572ddd3b56adf1" + resolved "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.5.tgz" integrity sha512-AguB9yvTXmCnySBP1lWjfNNUwpbElsaQ567lt2VdGqAdHtpieLgjmcVyv1q7PMIvLbgpDdkWV5Ydv3FEejyp2A== dependencies: "@adobe/css-tools" "^4.3.2" @@ -1299,7 +1299,7 @@ "@testing-library/react@^14.2.1": version "14.3.1" - resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-14.3.1.tgz#29513fc3770d6fb75245c4e1245c470e4ffdd830" + resolved "https://registry.npmjs.org/@testing-library/react/-/react-14.3.1.tgz" integrity sha512-H99XjUhWQw0lTgyMN05W3xQG1Nh4lq574D8keFf1dDoNTJgp66VbJozRaczoF+wsiaPJNt/TcnfpLGufGxSrZQ== dependencies: "@babel/runtime" "^7.12.5" @@ -1308,37 +1308,37 @@ "@tootallnate/once@2": version "2.0.0" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz" integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A== "@tsconfig/node10@^1.0.7": version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz" integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== "@tsconfig/node12@^1.0.7": version "1.0.11" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== "@tsconfig/node14@^1.0.0": version "1.0.3" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== "@tsconfig/node16@^1.0.2": version "1.0.4" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== "@types/aria-query@^5.0.1": version "5.0.4" - resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708" + resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz" integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw== "@types/babel__core@^7.1.14": version "7.20.5" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" @@ -1349,14 +1349,14 @@ "@types/babel__generator@*": version "7.6.8" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz" integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": version "7.4.4" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz" integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" @@ -1364,45 +1364,45 @@ "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": version "7.20.6" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz" integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: "@babel/types" "^7.20.7" "@types/canvas-confetti@1.4.0": version "1.4.0" - resolved "https://registry.yarnpkg.com/@types/canvas-confetti/-/canvas-confetti-1.4.0.tgz#22127a1a9ed9d456e626d6e2b9a4d3b0a240e18b" + resolved "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.4.0.tgz" integrity sha512-Neq4mvVecrHmTdyo98EY5bnKCjkZGQ6Ma7VyOrxIcMHEZPmt4kfquccqfBMrpNrdryMHgk3oGQi7XtpZacltnw== "@types/graceful-fs@^4.1.3": version "4.1.9" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz" integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz" integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz" integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" "@types/jest@^29.5.12": version "29.5.12" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.12.tgz#7f7dc6eb4cf246d2474ed78744b05d06ce025544" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz" integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== dependencies: expect "^29.0.0" @@ -1410,7 +1410,7 @@ "@types/jsdom@^20.0.0": version "20.0.1" - resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-20.0.1.tgz#07c14bc19bd2f918c1929541cdaacae894744808" + resolved "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz" integrity sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ== dependencies: "@types/node" "*" @@ -1419,48 +1419,41 @@ "@types/json-schema@^7.0.9": version "7.0.15" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/json5@^0.0.29": version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/lodash@^4.14.202": version "4.17.4" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.4.tgz#0303b64958ee070059e3a7184048a55159fe20b7" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.4.tgz" integrity sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ== -"@types/node@*": - version "20.12.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050" - integrity sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw== - dependencies: - undici-types "~5.26.4" - -"@types/node@20.14.10": +"@types/node@*", "@types/node@20.14.10": version "20.14.10" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.10.tgz#a1a218290f1b6428682e3af044785e5874db469a" + resolved "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz" integrity sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ== dependencies: undici-types "~5.26.4" "@types/prop-types@*": version "15.7.12" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" + resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz" integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== "@types/react-dom@^18", "@types/react-dom@^18.0.0": version "18.3.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.0.tgz#0cbc818755d87066ab6ca74fbedb2547d74a82b0" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz" integrity sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg== dependencies: "@types/react" "*" "@types/react@*", "@types/react@18.3.3": version "18.3.3" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f" + resolved "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz" integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw== dependencies: "@types/prop-types" "*" @@ -1468,46 +1461,46 @@ "@types/semver@^7.3.12": version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz" integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== "@types/stack-utils@^2.0.0": version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/stylis@4.2.5": version "4.2.5" - resolved "https://registry.yarnpkg.com/@types/stylis/-/stylis-4.2.5.tgz#1daa6456f40959d06157698a653a9ab0a70281df" + resolved "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz" integrity sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw== "@types/tough-cookie@*": version "4.0.5" - resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + resolved "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz" integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== "@types/yargs-parser@*": version "21.0.3" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^17.0.8": version "17.0.32" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz" integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^7.0.1": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz#07854a236f107bb45cbf4f62b89474cbea617f50" - integrity sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw== +"@typescript-eslint/eslint-plugin@^7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz" + integrity sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw== dependencies: "@eslint-community/regexpp" "^4.10.0" - "@typescript-eslint/scope-manager" "7.10.0" - "@typescript-eslint/type-utils" "7.10.0" - "@typescript-eslint/utils" "7.10.0" - "@typescript-eslint/visitor-keys" "7.10.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/type-utils" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" graphemer "^1.4.0" ignore "^5.3.1" natural-compare "^1.4.0" @@ -1515,7 +1508,7 @@ "@typescript-eslint/parser@^5.4.2 || ^6.0.0": version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz" integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== dependencies: "@typescript-eslint/scope-manager" "6.21.0" @@ -1524,20 +1517,20 @@ "@typescript-eslint/visitor-keys" "6.21.0" debug "^4.3.4" -"@typescript-eslint/parser@^7.0.1": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.10.0.tgz#e6ac1cba7bc0400a4459e7eb5b23115bd71accfb" - integrity sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w== +"@typescript-eslint/parser@^7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz" + integrity sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg== dependencies: - "@typescript-eslint/scope-manager" "7.10.0" - "@typescript-eslint/types" "7.10.0" - "@typescript-eslint/typescript-estree" "7.10.0" - "@typescript-eslint/visitor-keys" "7.10.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" debug "^4.3.4" "@typescript-eslint/scope-manager@5.62.0": version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz" integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== dependencies: "@typescript-eslint/types" "5.62.0" @@ -1545,48 +1538,48 @@ "@typescript-eslint/scope-manager@6.21.0": version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz" integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== dependencies: "@typescript-eslint/types" "6.21.0" "@typescript-eslint/visitor-keys" "6.21.0" -"@typescript-eslint/scope-manager@7.10.0": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz#054a27b1090199337a39cf755f83d9f2ce26546b" - integrity sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg== +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== dependencies: - "@typescript-eslint/types" "7.10.0" - "@typescript-eslint/visitor-keys" "7.10.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" -"@typescript-eslint/type-utils@7.10.0": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.10.0.tgz#8a75accce851d0a331aa9331268ef64e9b300270" - integrity sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g== +"@typescript-eslint/type-utils@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz" + integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== dependencies: - "@typescript-eslint/typescript-estree" "7.10.0" - "@typescript-eslint/utils" "7.10.0" + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/utils" "7.18.0" debug "^4.3.4" ts-api-utils "^1.3.0" "@typescript-eslint/types@5.62.0": version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== "@typescript-eslint/types@6.21.0": version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz" integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== -"@typescript-eslint/types@7.10.0": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.10.0.tgz#da92309c97932a3a033762fd5faa8b067de84e3b" - integrity sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg== +"@typescript-eslint/types@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz" integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== dependencies: "@typescript-eslint/types" "5.62.0" @@ -1599,7 +1592,7 @@ "@typescript-eslint/typescript-estree@6.21.0": version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz" integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== dependencies: "@typescript-eslint/types" "6.21.0" @@ -1611,13 +1604,13 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/typescript-estree@7.10.0": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz#6dcdc5de3149916a6a599fa89dde5c471b88b8bb" - integrity sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g== +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== dependencies: - "@typescript-eslint/types" "7.10.0" - "@typescript-eslint/visitor-keys" "7.10.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -1625,19 +1618,19 @@ semver "^7.6.0" ts-api-utils "^1.3.0" -"@typescript-eslint/utils@7.10.0": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.10.0.tgz#8ee43e5608c9f439524eaaea8de5b358b15c51b3" - integrity sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg== +"@typescript-eslint/utils@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@typescript-eslint/scope-manager" "7.10.0" - "@typescript-eslint/types" "7.10.0" - "@typescript-eslint/typescript-estree" "7.10.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" "@typescript-eslint/utils@^5.10.0": version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz" integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" @@ -1651,7 +1644,7 @@ "@typescript-eslint/visitor-keys@5.62.0": version "5.62.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz" integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== dependencies: "@typescript-eslint/types" "5.62.0" @@ -1659,33 +1652,33 @@ "@typescript-eslint/visitor-keys@6.21.0": version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz" integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== dependencies: "@typescript-eslint/types" "6.21.0" eslint-visitor-keys "^3.4.1" -"@typescript-eslint/visitor-keys@7.10.0": - version "7.10.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz#2af2e91e73a75dd6b70b4486c48ae9d38a485a78" - integrity sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg== +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== dependencies: - "@typescript-eslint/types" "7.10.0" + "@typescript-eslint/types" "7.18.0" eslint-visitor-keys "^3.4.3" "@ungap/structured-clone@^1.2.0": version "1.2.0" - resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz" integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== abab@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== acorn-globals@^7.0.0: version "7.0.1" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-7.0.1.tgz#0dbf05c44fa7c94332914c02066d5beff62c40c3" + resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz" integrity sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q== dependencies: acorn "^8.1.0" @@ -1693,34 +1686,34 @@ acorn-globals@^7.0.0: acorn-jsx@^5.3.2: version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.0.2, acorn-walk@^8.1.1: version "8.3.2" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz" integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== acorn@^8.1.0, acorn@^8.4.1, acorn@^8.8.1, acorn@^8.9.0: version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== aes-js@3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-3.0.0.tgz#e21df10ad6c2053295bcbb8dab40b09dbea87e4d" + resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz" integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== agent-base@6: version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" ajv@^6.12.4: version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -1730,48 +1723,48 @@ ajv@^6.12.4: ansi-escapes@^4.2.1: version "4.3.2" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" ansi-styles@^5.0.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== ansi-styles@^6.1.0: version "6.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== antd@^5.14.0: version "5.17.3" - resolved "https://registry.yarnpkg.com/antd/-/antd-5.17.3.tgz#c969755335cdef6fa671152602b7100557bff80c" + resolved "https://registry.npmjs.org/antd/-/antd-5.17.3.tgz" integrity sha512-U99hyy7t8dOQtNHzHifmwAXJLgmPMadavFBsd2mnfICD6m8l7u/NvCefRhd2jOf/SBNE2579YhwCEwTUiX2GnQ== dependencies: "@ant-design/colors" "^7.0.2" @@ -1825,7 +1818,7 @@ antd@^5.14.0: anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" @@ -1833,38 +1826,38 @@ anymatch@^3.0.3, anymatch@~3.1.2: arg@^4.1.0: version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== argparse@^1.0.7: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" argparse@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== aria-query@5.1.3: version "5.1.3" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.1.3.tgz#19db27cd101152773631396f7a95a3b58c22c35e" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz" integrity sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ== dependencies: deep-equal "^2.0.5" aria-query@^5.0.0, aria-query@^5.3.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + resolved "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz" integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== dependencies: dequal "^2.0.3" array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz" integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== dependencies: call-bind "^1.0.5" @@ -1872,7 +1865,7 @@ array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: array-includes@^3.1.6, array-includes@^3.1.7: version "3.1.8" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz" integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== dependencies: call-bind "^1.0.7" @@ -1884,17 +1877,17 @@ array-includes@^3.1.6, array-includes@^3.1.7: array-tree-filter@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" + resolved "https://registry.npmjs.org/array-tree-filter/-/array-tree-filter-2.1.0.tgz" integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw== array-union@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== array.prototype.findlast@^1.2.4: version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + resolved "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz" integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== dependencies: call-bind "^1.0.7" @@ -1906,7 +1899,7 @@ array.prototype.findlast@^1.2.4: array.prototype.findlastindex@^1.2.3: version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + resolved "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz" integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== dependencies: call-bind "^1.0.7" @@ -1918,7 +1911,7 @@ array.prototype.findlastindex@^1.2.3: array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz" integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== dependencies: call-bind "^1.0.2" @@ -1928,7 +1921,7 @@ array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2: array.prototype.flatmap@^1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz" integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== dependencies: call-bind "^1.0.2" @@ -1938,7 +1931,7 @@ array.prototype.flatmap@^1.3.2: array.prototype.toreversed@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz#b989a6bf35c4c5051e1dc0325151bf8088954eba" + resolved "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz" integrity sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA== dependencies: call-bind "^1.0.2" @@ -1948,7 +1941,7 @@ array.prototype.toreversed@^1.1.2: array.prototype.tosorted@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz#c8c89348337e51b8a3c48a9227f9ce93ceedcba8" + resolved "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz" integrity sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg== dependencies: call-bind "^1.0.5" @@ -1959,7 +1952,7 @@ array.prototype.tosorted@^1.1.3: arraybuffer.prototype.slice@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz" integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== dependencies: array-buffer-byte-length "^1.0.1" @@ -1973,29 +1966,29 @@ arraybuffer.prototype.slice@^1.0.3: ast-types-flow@^0.0.8: version "0.0.8" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz" integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== available-typed-arrays@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz" integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== dependencies: possible-typed-array-names "^1.0.0" axe-core@=4.7.0: version "4.7.0" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" + resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz" integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== axios@^1.7.7: version "1.7.7" - resolved "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + resolved "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz" integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" @@ -2004,14 +1997,14 @@ axios@^1.7.7: axobject-query@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-3.2.1.tgz#39c378a6e3b06ca679f29138151e45b2b32da62a" + resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz" integrity sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg== dependencies: dequal "^2.0.3" babel-jest@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: "@jest/transform" "^29.7.0" @@ -2024,7 +2017,7 @@ babel-jest@^29.7.0: babel-plugin-istanbul@^6.1.1: version "6.1.1" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -2035,7 +2028,7 @@ babel-plugin-istanbul@^6.1.1: babel-plugin-jest-hoist@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz" integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" @@ -2045,7 +2038,7 @@ babel-plugin-jest-hoist@^29.6.3: babel-preset-current-node-syntax@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" @@ -2063,7 +2056,7 @@ babel-preset-current-node-syntax@^1.0.0: babel-preset-jest@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: babel-plugin-jest-hoist "^29.6.3" @@ -2071,32 +2064,32 @@ babel-preset-jest@^29.6.3: balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== bech32@1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/bech32/-/bech32-1.1.4.tgz#e38c9f37bf179b8eb16ae3a772b40c356d4832e9" + resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== binary-extensions@^2.0.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== bn.js@^4.11.9: version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== bn.js@^5.2.1: version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -2104,26 +2097,26 @@ brace-expansion@^1.1.7: brace-expansion@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" braces@^3.0.3, braces@~3.0.2: version "3.0.3" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" brorand@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== browserslist@^4.22.2: version "4.23.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== dependencies: caniuse-lite "^1.0.30001587" @@ -2133,26 +2126,26 @@ browserslist@^4.22.2: bser@2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" buffer-from@^1.0.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== busboy@1.6.0: version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" + resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz" integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== dependencies: streamsearch "^1.1.0" call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== dependencies: es-define-property "^1.0.0" @@ -2163,37 +2156,37 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: callsites@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== camelcase@^5.3.1: version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.2.0: version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== camelize@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3" + resolved "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz" integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ== caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001587: version "1.0.30001621" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz#4adcb443c8b9c8303e04498318f987616b8fea2e" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001621.tgz" integrity sha512-+NLXZiviFFKX0fk8Piwv3PfLPGtRqJeq2TiNoUff/qB5KJgwecJTvCXDpmlyP/eCI/GUEmp/h/y5j0yckiiZrA== canvas-confetti@1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/canvas-confetti/-/canvas-confetti-1.4.0.tgz#840f6db4a566f8f32abe28c00dcd82acf39c92bd" + resolved "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.4.0.tgz" integrity sha512-S18o4Y9PqI/uabdlT/jI3MY7XBJjNxnfapFIkjkMwpz6qNxLFZOm2b22OMf4ZYDL9lpNWI+Ih4fEMVPwO1KHFQ== chalk@^2.4.2: version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -2202,7 +2195,7 @@ chalk@^2.4.2: chalk@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz" integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== dependencies: ansi-styles "^4.1.0" @@ -2210,7 +2203,7 @@ chalk@^3.0.0: chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -2218,12 +2211,12 @@ chalk@^4.0.0, chalk@^4.1.0: char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== "chokidar@>=3.0.0 <4.0.0": version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" @@ -2238,27 +2231,27 @@ char-regex@^1.0.2: ci-info@^3.2.0: version "3.9.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz#c485341ae8fd999ca4ee5af2d7a1c9ae01e0099c" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz" integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1: version "2.5.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== client-only@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== cliui@^8.0.1: version "8.0.1" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== dependencies: string-width "^4.2.0" @@ -2267,70 +2260,70 @@ cliui@^8.0.1: co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== collect-v8-coverage@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== combined-stream@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" compute-scroll-into-view@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz#753f11d972596558d8fe7c6bcbc8497690ab4c87" + resolved "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz" integrity sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg== concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== convert-source-map@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== copy-to-clipboard@^3.3.3: version "3.3.3" - resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz#55ac43a1db8ae639a4bd99511c148cdd1b83a1b0" + resolved "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz" integrity sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA== dependencies: toggle-selection "^1.0.6" create-jest@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz" integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== dependencies: "@jest/types" "^29.6.3" @@ -2343,19 +2336,19 @@ create-jest@^29.7.0: create-require@^1.1.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== cross-fetch@^3.1.5: version "3.1.8" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz" integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== dependencies: node-fetch "^2.6.12" cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -2364,12 +2357,12 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: css-color-keywords@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + resolved "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz" integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg== css-to-react-native@3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32" + resolved "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz" integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ== dependencies: camelize "^1.0.0" @@ -2378,39 +2371,39 @@ css-to-react-native@3.2.0: css.escape@^1.5.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" + resolved "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz" integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg== cssom@^0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz" integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== cssom@~0.3.6: version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== cssstyle@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== dependencies: cssom "~0.3.6" csstype@3.1.3, csstype@^3.0.2, csstype@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== damerau-levenshtein@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + resolved "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz" integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== data-urls@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz" integrity sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ== dependencies: abab "^2.0.6" @@ -2419,7 +2412,7 @@ data-urls@^3.0.2: data-view-buffer@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + resolved "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz" integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== dependencies: call-bind "^1.0.6" @@ -2428,7 +2421,7 @@ data-view-buffer@^1.0.1: data-view-byte-length@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + resolved "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz" integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== dependencies: call-bind "^1.0.7" @@ -2437,7 +2430,7 @@ data-view-byte-length@^1.0.1: data-view-byte-offset@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + resolved "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz" integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== dependencies: call-bind "^1.0.6" @@ -2446,36 +2439,36 @@ data-view-byte-offset@^1.0.0: dayjs@^1.11.10: version "1.11.11" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e" + resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz" integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== dependencies: ms "2.1.2" debug@^3.2.7: version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" decimal.js@^10.4.2: version "10.4.3" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz" integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== dedent@^1.0.0: version "1.5.3" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz" integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-equal@^2.0.5: version "2.2.3" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-2.2.3.tgz#af89dafb23a396c7da3e862abc0be27cf51d56e1" + resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz" integrity sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA== dependencies: array-buffer-byte-length "^1.0.0" @@ -2499,17 +2492,17 @@ deep-equal@^2.0.5: deep-is@^0.1.3: version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== deepmerge@^4.2.2: version "4.3.1" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== dependencies: es-define-property "^1.0.0" @@ -2518,7 +2511,7 @@ define-data-property@^1.0.1, define-data-property@^1.1.4: define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== dependencies: define-data-property "^1.0.1" @@ -2527,80 +2520,80 @@ define-properties@^1.2.0, define-properties@^1.2.1: delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== dequal@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + resolved "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== detect-newline@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== diff-sequences@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz" integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== diff@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== dir-glob@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: path-type "^4.0.0" doctrine@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" doctrine@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== dependencies: esutils "^2.0.2" dom-accessibility-api@^0.5.9: version "0.5.16" - resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453" + resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz" integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg== dom-accessibility-api@^0.6.3: version "0.6.3" - resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz#993e925cc1d73f2c662e7d75dd5a5445259a8fd8" + resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz" integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w== domexception@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + resolved "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz" integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== dependencies: webidl-conversions "^7.0.0" eastasianwidth@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== electron-to-chromium@^1.4.668: version "1.4.780" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.780.tgz#8c6d7ff82b56b4219f2ae7918ee271ae25654f07" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.780.tgz" integrity sha512-NPtACGFe7vunRYzvYqVRhQvsDrTevxpgDKxG/Vcbe0BTNOY+5+/2mOXSw2ls7ToNbE5Bf/+uQbjTxcmwMozpCw== elliptic@6.5.4: version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== dependencies: bn.js "^4.11.9" @@ -2613,22 +2606,22 @@ elliptic@6.5.4: emittery@^0.13.1: version "0.13.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== emoji-regex@^9.2.2: version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== enhanced-resolve@^5.12.0: version "5.16.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz#e8bc63d51b826d6f1cbc0a150ecb5a8b0c62e567" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz" integrity sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw== dependencies: graceful-fs "^4.2.4" @@ -2636,19 +2629,19 @@ enhanced-resolve@^5.12.0: entities@^4.4.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== error-ex@^1.3.1: version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.1, es-abstract@^1.23.2, es-abstract@^1.23.3: version "1.23.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz" integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== dependencies: array-buffer-byte-length "^1.0.1" @@ -2700,19 +2693,19 @@ es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23 es-define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz" integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== dependencies: get-intrinsic "^1.2.4" es-errors@^1.1.0, es-errors@^1.2.1, es-errors@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== es-get-iterator@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz#3ef87523c5d464d41084b2c3c9c214f1199763d6" + resolved "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz" integrity sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw== dependencies: call-bind "^1.0.2" @@ -2727,7 +2720,7 @@ es-get-iterator@^1.1.3: es-iterator-helpers@^1.0.15, es-iterator-helpers@^1.0.17: version "1.0.19" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz#117003d0e5fec237b4b5c08aded722e0c6d50ca8" + resolved "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz" integrity sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw== dependencies: call-bind "^1.0.7" @@ -2747,14 +2740,14 @@ es-iterator-helpers@^1.0.15, es-iterator-helpers@^1.0.17: es-object-atoms@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz" integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== dependencies: es-errors "^1.3.0" es-set-tostringtag@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz" integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== dependencies: get-intrinsic "^1.2.4" @@ -2763,14 +2756,14 @@ es-set-tostringtag@^2.0.3: es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz" integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== dependencies: hasown "^2.0.0" es-to-primitive@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== dependencies: is-callable "^1.1.4" @@ -2779,27 +2772,27 @@ es-to-primitive@^1.2.1: escalade@^3.1.1, escalade@^3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== escape-string-regexp@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== escodegen@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz" integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== dependencies: esprima "^4.0.1" @@ -2810,7 +2803,7 @@ escodegen@^2.0.0: eslint-config-next@14.1.0: version "14.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-14.1.0.tgz#7e309d426b8afacaba3b32fdbb02ba220b6d0a97" + resolved "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.1.0.tgz" integrity sha512-SBX2ed7DoRFXC6CQSLc/SbLY9Ut6HxNB2wPTcoIWjUMd7aF7O/SIE7111L8FdZ9TXsNV4pulUDnfthpyPtbFUg== dependencies: "@next/eslint-plugin-next" "14.1.0" @@ -2825,12 +2818,12 @@ eslint-config-next@14.1.0: eslint-config-prettier@^9.1.0: version "9.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + resolved "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz" integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: version "0.3.9" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz" integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== dependencies: debug "^3.2.7" @@ -2839,7 +2832,7 @@ eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: eslint-import-resolver-typescript@^3.5.2: version "3.6.1" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz#7b983680edd3f1c5bce1a5829ae0bc2d57fe9efa" + resolved "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz" integrity sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg== dependencies: debug "^4.3.4" @@ -2852,14 +2845,14 @@ eslint-import-resolver-typescript@^3.5.2: eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: version "2.8.1" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz#52f2404300c3bd33deece9d7372fb337cc1d7c34" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz" integrity sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q== dependencies: debug "^3.2.7" eslint-plugin-import@^2.28.1, eslint-plugin-import@^2.29.1: version "2.29.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz#d45b37b5ef5901d639c15270d74d46d161150643" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz" integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== dependencies: array-includes "^3.1.7" @@ -2882,14 +2875,14 @@ eslint-plugin-import@^2.28.1, eslint-plugin-import@^2.29.1: eslint-plugin-jest@^27.6.3: version "27.9.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz#7c98a33605e1d8b8442ace092b60e9919730000b" + resolved "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz" integrity sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug== dependencies: "@typescript-eslint/utils" "^5.10.0" eslint-plugin-jsx-a11y@^6.7.1: version "6.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz#2fa9c701d44fcd722b7c771ec322432857fcbad2" + resolved "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz" integrity sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA== dependencies: "@babel/runtime" "^7.23.2" @@ -2911,12 +2904,12 @@ eslint-plugin-jsx-a11y@^6.7.1: eslint-plugin-next@^0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-next/-/eslint-plugin-next-0.0.0.tgz#f9ef680e8f68763c716ab44697c4b3cc3e0b2069" + resolved "https://registry.npmjs.org/eslint-plugin-next/-/eslint-plugin-next-0.0.0.tgz" integrity sha512-IldNDVb6WNduggwRbYzSGZhaskUwVecJ6fhmqwX01+S1aohwAWNzU4me6y47DDzpD/g0fdayNBGxEdt9vKkUtg== eslint-plugin-prettier@^5.1.3: version "5.1.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz#17cfade9e732cef32b5f5be53bd4e07afd8e67e1" + resolved "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz" integrity sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw== dependencies: prettier-linter-helpers "^1.0.0" @@ -2924,12 +2917,12 @@ eslint-plugin-prettier@^5.1.3: "eslint-plugin-react-hooks@^4.5.0 || 5.0.0-canary-7118f5dd7-20230705": version "4.6.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596" + resolved "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz" integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ== eslint-plugin-react@^7.33.2: version "7.34.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz#6806b70c97796f5bbfb235a5d3379ece5f4da997" + resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz" integrity sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw== dependencies: array-includes "^3.1.7" @@ -2953,24 +2946,24 @@ eslint-plugin-react@^7.33.2: eslint-plugin-simple-import-sort@^12.0.0: version "12.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.0.tgz#8186ad55474d2f5c986a2f1bf70625a981e30d05" + resolved "https://registry.npmjs.org/eslint-plugin-simple-import-sort/-/eslint-plugin-simple-import-sort-12.1.0.tgz" integrity sha512-Y2fqAfC11TcG/WP3TrI1Gi3p3nc8XJyEOJYHyEPEGI/UAgNx6akxxlX74p7SbAQdLcgASKhj8M0GKvH3vq/+ig== eslint-plugin-unused-imports@^3.0.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz#63a98c9ad5f622cd9f830f70bc77739f25ccfe0d" + resolved "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz" integrity sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ== dependencies: eslint-rule-composer "^0.3.0" eslint-rule-composer@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + resolved "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz" integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== eslint-scope@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== dependencies: esrecurse "^4.3.0" @@ -2978,7 +2971,7 @@ eslint-scope@^5.1.1: eslint-scope@^7.2.2: version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== dependencies: esrecurse "^4.3.0" @@ -2986,12 +2979,12 @@ eslint-scope@^7.2.2: eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== eslint@^8.56.0: version "8.57.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz" integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" @@ -3035,7 +3028,7 @@ eslint@^8.56.0: espree@^9.6.0, espree@^9.6.1: version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: acorn "^8.9.0" @@ -3044,48 +3037,48 @@ espree@^9.6.0, espree@^9.6.1: esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.4.2: version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== dependencies: estraverse "^5.1.0" esrecurse@^4.3.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== dependencies: estraverse "^5.2.0" estraverse@^4.1.1: version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== ethers-multicall@^0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/ethers-multicall/-/ethers-multicall-0.2.3.tgz#872b5ad7d6b5d4d7f2960c33bf36bd46d034ac41" + resolved "https://registry.npmjs.org/ethers-multicall/-/ethers-multicall-0.2.3.tgz" integrity sha512-RaWQuLy+HzeKOibptlc9RZ6j7bT1H6VnkdAKTHiLx2t/lpyfS2ckXHdQhhRbCaXNc1iu6CgoisgMejxKHg84tg== dependencies: ethers "^5.0.0" ethers@5.7.2, ethers@^5.0.0: version "5.7.2" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" + resolved "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== dependencies: "@ethersproject/abi" "5.7.0" @@ -3121,7 +3114,7 @@ ethers@5.7.2, ethers@^5.0.0: execa@^5.0.0: version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -3136,12 +3129,12 @@ execa@^5.0.0: exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== expect@^29.0.0, expect@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz" integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: "@jest/expect-utils" "^29.7.0" @@ -3152,17 +3145,17 @@ expect@^29.0.0, expect@^29.7.0: fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-diff@^1.1.2: version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + resolved "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== fast-glob@^3.2.9, fast-glob@^3.3.1: version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -3173,45 +3166,45 @@ fast-glob@^3.2.9, fast-glob@^3.3.1: fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: version "1.17.1" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz" integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== dependencies: reusify "^1.0.4" fb-watchman@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== dependencies: bser "2.1.1" file-entry-cache@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== dependencies: flat-cache "^3.0.4" fill-range@^7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" @@ -3219,7 +3212,7 @@ find-up@^4.0.0, find-up@^4.1.0: find-up@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: locate-path "^6.0.0" @@ -3227,7 +3220,7 @@ find-up@^5.0.0: flat-cache@^3.0.4: version "3.2.0" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== dependencies: flatted "^3.2.9" @@ -3236,24 +3229,24 @@ flat-cache@^3.0.4: flatted@^3.2.9: version "3.3.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== follow-redirects@^1.15.6: version "1.15.9" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== for-each@^0.3.3: version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== dependencies: is-callable "^1.1.3" foreground-child@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== dependencies: cross-spawn "^7.0.0" @@ -3261,7 +3254,7 @@ foreground-child@^3.1.0: form-data@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== dependencies: asynckit "^0.4.0" @@ -3270,22 +3263,22 @@ form-data@^4.0.0: fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz" integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== dependencies: call-bind "^1.0.2" @@ -3295,22 +3288,22 @@ function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: functions-have-names@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== gensync@^1.0.0-beta.2: version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== dependencies: es-errors "^1.3.0" @@ -3321,17 +3314,17 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@ get-package-type@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== get-stream@^6.0.0: version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== get-symbol-description@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz" integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== dependencies: call-bind "^1.0.5" @@ -3340,28 +3333,28 @@ get-symbol-description@^1.0.2: get-tsconfig@^4.5.0: version "4.7.5" - resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.5.tgz#5e012498579e9a6947511ed0cd403272c7acbbaf" + resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz" integrity sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw== dependencies: resolve-pkg-maps "^1.0.0" glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" glob-parent@^6.0.2: version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== dependencies: is-glob "^4.0.3" glob@10.3.10: version "10.3.10" - resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + resolved "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz" integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== dependencies: foreground-child "^3.1.0" @@ -3372,7 +3365,7 @@ glob@10.3.10: glob@^7.1.3, glob@^7.1.4: version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== dependencies: fs.realpath "^1.0.0" @@ -3384,19 +3377,19 @@ glob@^7.1.3, glob@^7.1.4: globals@^11.1.0: version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^13.19.0: version "13.24.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" globalthis@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz" integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: define-properties "^1.2.1" @@ -3404,7 +3397,7 @@ globalthis@^1.0.3: globby@^11.1.0: version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" @@ -3416,24 +3409,24 @@ globby@^11.1.0: gopd@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== dependencies: get-intrinsic "^1.1.3" graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== graphemer@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== graphql-request@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f" + resolved "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz" integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw== dependencies: "@graphql-typed-document-node/core" "^3.2.0" @@ -3441,51 +3434,51 @@ graphql-request@^6.1.0: graphql@^16.8.1: version "16.9.0" - resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.9.0.tgz#1c310e63f16a49ce1fbb230bd0a000e99f6f115f" + resolved "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz" integrity sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw== has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== dependencies: es-define-property "^1.0.0" has-proto@^1.0.1, has-proto@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== dependencies: has-symbols "^1.0.3" hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== dependencies: inherits "^2.0.3" @@ -3493,14 +3486,14 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" hmac-drbg@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== dependencies: hash.js "^1.0.3" @@ -3509,19 +3502,19 @@ hmac-drbg@^1.0.1: html-encoding-sniffer@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz" integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== dependencies: whatwg-encoding "^2.0.0" html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== http-proxy-agent@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz" integrity sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w== dependencies: "@tootallnate/once" "2" @@ -3530,7 +3523,7 @@ http-proxy-agent@^5.0.0: https-proxy-agent@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== dependencies: agent-base "6" @@ -3538,29 +3531,29 @@ https-proxy-agent@^5.0.1: human-signals@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== iconv-lite@0.6.3: version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" ignore@^5.2.0, ignore@^5.3.1: version "5.3.1" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== immutable@^4.0.0: version "4.3.6" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.6.tgz#6a05f7858213238e587fb83586ffa3b4b27f0447" + resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz" integrity sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ== import-fresh@^3.2.1: version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" @@ -3568,7 +3561,7 @@ import-fresh@^3.2.1: import-local@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== dependencies: pkg-dir "^4.2.0" @@ -3576,17 +3569,17 @@ import-local@^3.0.2: imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" @@ -3594,12 +3587,12 @@ inflight@^1.0.4: inherits@2, inherits@^2.0.3, inherits@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== internal-slot@^1.0.4, internal-slot@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz" integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== dependencies: es-errors "^1.3.0" @@ -3608,7 +3601,7 @@ internal-slot@^1.0.4, internal-slot@^1.0.7: is-arguments@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + resolved "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz" integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== dependencies: call-bind "^1.0.2" @@ -3616,7 +3609,7 @@ is-arguments@^1.1.1: is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz" integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== dependencies: call-bind "^1.0.2" @@ -3624,33 +3617,33 @@ is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-async-function@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + resolved "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz" integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== dependencies: has-tostringtag "^1.0.0" is-bigint@^1.0.1: version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== dependencies: has-bigints "^1.0.1" is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" is-boolean-object@^1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== dependencies: call-bind "^1.0.2" @@ -3658,101 +3651,101 @@ is-boolean-object@^1.1.0: is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: hasown "^2.0.0" is-data-view@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + resolved "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz" integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== dependencies: is-typed-array "^1.1.13" is-date-object@^1.0.1, is-date-object@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== dependencies: has-tostringtag "^1.0.0" is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-finalizationregistry@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz#c8749b65f17c133313e661b1289b95ad3dbd62e6" + resolved "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz" integrity sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw== dependencies: call-bind "^1.0.2" is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-fn@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== is-generator-function@^1.0.10: version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + resolved "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz" integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== dependencies: has-tostringtag "^1.0.0" is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" is-map@^2.0.2, is-map@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + resolved "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz" integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== is-negative-zero@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz" integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== dependencies: has-tostringtag "^1.0.0" is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 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" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== is-potential-custom-element-name@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== is-regex@^1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: call-bind "^1.0.2" @@ -3760,57 +3753,57 @@ is-regex@^1.1.4: is-set@^2.0.2, is-set@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + resolved "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz" integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz" integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== dependencies: call-bind "^1.0.7" is-stream@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== dependencies: has-tostringtag "^1.0.0" is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== dependencies: has-symbols "^1.0.2" is-typed-array@^1.1.13: version "1.1.13" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz" integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: which-typed-array "^1.1.14" is-weakmap@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + resolved "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz" integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== is-weakref@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== dependencies: call-bind "^1.0.2" is-weakset@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.3.tgz#e801519df8c0c43e12ff2834eead84ec9e624007" + resolved "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz" integrity sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ== dependencies: call-bind "^1.0.7" @@ -3818,22 +3811,22 @@ is-weakset@^2.0.3: isarray@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== istanbul-lib-instrument@^5.0.4: version "5.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== dependencies: "@babel/core" "^7.12.3" @@ -3844,7 +3837,7 @@ istanbul-lib-instrument@^5.0.4: istanbul-lib-instrument@^6.0.0: version "6.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz#91655936cf7380e4e473383081e38478b69993b1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz" integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== dependencies: "@babel/core" "^7.23.9" @@ -3855,7 +3848,7 @@ istanbul-lib-instrument@^6.0.0: istanbul-lib-report@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: istanbul-lib-coverage "^3.0.0" @@ -3864,7 +3857,7 @@ istanbul-lib-report@^3.0.0: istanbul-lib-source-maps@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" @@ -3873,7 +3866,7 @@ istanbul-lib-source-maps@^4.0.0: istanbul-reports@^3.1.3: version "3.1.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz" integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" @@ -3881,7 +3874,7 @@ istanbul-reports@^3.1.3: iterator.prototype@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + resolved "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz" integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== dependencies: define-properties "^1.2.1" @@ -3892,7 +3885,7 @@ iterator.prototype@^1.1.2: jackspeak@^2.3.5: version "2.3.6" - resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz" integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== dependencies: "@isaacs/cliui" "^8.0.2" @@ -3901,7 +3894,7 @@ jackspeak@^2.3.5: jest-changed-files@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz" integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: execa "^5.0.0" @@ -3910,7 +3903,7 @@ jest-changed-files@^29.7.0: jest-circus@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== dependencies: "@jest/environment" "^29.7.0" @@ -3936,7 +3929,7 @@ jest-circus@^29.7.0: jest-cli@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz" integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: "@jest/core" "^29.7.0" @@ -3953,7 +3946,7 @@ jest-cli@^29.7.0: jest-config@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz" integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: "@babel/core" "^7.11.6" @@ -3981,7 +3974,7 @@ jest-config@^29.7.0: jest-diff@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: chalk "^4.0.0" @@ -3991,14 +3984,14 @@ jest-diff@^29.7.0: jest-docblock@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz" integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: detect-newline "^3.0.0" jest-each@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz" integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: "@jest/types" "^29.6.3" @@ -4009,7 +4002,7 @@ jest-each@^29.7.0: jest-environment-jsdom@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz#d206fa3551933c3fd519e5dfdb58a0f5139a837f" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz" integrity sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA== dependencies: "@jest/environment" "^29.7.0" @@ -4023,7 +4016,7 @@ jest-environment-jsdom@^29.7.0: jest-environment-node@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz" integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== dependencies: "@jest/environment" "^29.7.0" @@ -4035,12 +4028,12 @@ jest-environment-node@^29.7.0: jest-get-type@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz" integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== jest-haste-map@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz" integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: "@jest/types" "^29.6.3" @@ -4059,7 +4052,7 @@ jest-haste-map@^29.7.0: jest-leak-detector@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz" integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: jest-get-type "^29.6.3" @@ -4067,7 +4060,7 @@ jest-leak-detector@^29.7.0: jest-matcher-utils@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz" integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: chalk "^4.0.0" @@ -4077,7 +4070,7 @@ jest-matcher-utils@^29.7.0: jest-message-util@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: "@babel/code-frame" "^7.12.13" @@ -4092,7 +4085,7 @@ jest-message-util@^29.7.0: jest-mock@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: "@jest/types" "^29.6.3" @@ -4101,17 +4094,17 @@ jest-mock@^29.7.0: jest-pnp-resolver@^1.2.2: version "1.2.3" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== jest-regex-util@^29.6.3: version "29.6.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz" integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== jest-resolve-dependencies@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz" integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: jest-regex-util "^29.6.3" @@ -4119,7 +4112,7 @@ jest-resolve-dependencies@^29.7.0: jest-resolve@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: chalk "^4.0.0" @@ -4134,7 +4127,7 @@ jest-resolve@^29.7.0: jest-runner@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: "@jest/console" "^29.7.0" @@ -4161,7 +4154,7 @@ jest-runner@^29.7.0: jest-runtime@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz" integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== dependencies: "@jest/environment" "^29.7.0" @@ -4189,7 +4182,7 @@ jest-runtime@^29.7.0: jest-snapshot@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz" integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: "@babel/core" "^7.11.6" @@ -4215,7 +4208,7 @@ jest-snapshot@^29.7.0: jest-util@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: "@jest/types" "^29.6.3" @@ -4227,7 +4220,7 @@ jest-util@^29.7.0: jest-validate@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz" integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: "@jest/types" "^29.6.3" @@ -4239,7 +4232,7 @@ jest-validate@^29.7.0: jest-watcher@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz" integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: "@jest/test-result" "^29.7.0" @@ -4253,7 +4246,7 @@ jest-watcher@^29.7.0: jest-worker@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" @@ -4263,7 +4256,7 @@ jest-worker@^29.7.0: jest@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: "@jest/core" "^29.7.0" @@ -4273,17 +4266,17 @@ jest@^29.7.0: js-sha3@0.8.0: version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" @@ -4291,14 +4284,14 @@ js-yaml@^3.13.1: js-yaml@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" jsdom@^20.0.0: version "20.0.3" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz" integrity sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ== dependencies: abab "^2.0.6" @@ -4330,51 +4323,51 @@ jsdom@^20.0.0: jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== json-buffer@3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== json-parse-even-better-errors@^2.3.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== json2mq@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" + resolved "https://registry.npmjs.org/json2mq/-/json2mq-0.2.0.tgz" integrity sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA== dependencies: string-convert "^0.2.0" json5@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" json5@^2.2.3: version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: version "3.3.5" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz" integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== dependencies: array-includes "^3.1.6" @@ -4384,36 +4377,36 @@ json5@^2.2.3: keyv@^4.5.3: version "4.5.4" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== dependencies: json-buffer "3.0.1" kleur@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== language-subtag-registry@^0.3.20: version "0.3.23" - resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" + resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz" integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ== language-tags@^1.0.9: version "1.0.9" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + resolved "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz" integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== dependencies: language-subtag-registry "^0.3.20" leven@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== levn@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== dependencies: prelude-ls "^1.2.1" @@ -4421,94 +4414,94 @@ levn@^0.4.1: lines-and-columns@^1.1.6: version "1.2.4" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== locate-path@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" lodash.debounce@^4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== lodash.merge@^4.6.2: version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== lodash@^4.17.21: version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" lru-cache@^10.2.0: version "10.2.2" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz" integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" lz-string@^1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" + resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz" integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== make-dir@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== dependencies: semver "^7.5.3" make-error@^1.1.1: version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== makeerror@1.0.12: version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: tmpl "1.0.5" merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== micromatch@^4.0.4: version "4.0.7" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz" integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== dependencies: braces "^3.0.3" @@ -4516,90 +4509,97 @@ micromatch@^4.0.4: mime-db@1.52.0: version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== mime-types@^2.1.12: version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== min-indent@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== minimalistic-crypto-utils@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== minimatch@9.0.3: version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: brace-expansion "^2.0.1" minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@^9.0.1, minimatch@^9.0.4: +minimatch@^9.0.1: version "9.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": version "7.1.1" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.1.tgz#f7f85aff59aa22f110b20e27692465cf3bf89481" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz" integrity sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA== ms@2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== ms@^2.1.1: version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== nanoid@^3.3.6, nanoid@^3.3.7: version "3.3.7" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== next@^14.2.3: version "14.2.3" - resolved "https://registry.yarnpkg.com/next/-/next-14.2.3.tgz#f117dd5d5f20c307e7b8e4f9c1c97d961008925d" + resolved "https://registry.npmjs.org/next/-/next-14.2.3.tgz" integrity sha512-dowFkFTR8v79NPJO4QsBUtxv0g9BrS/phluVpMAt2ku7H+cbcBJlopXjkWlwxrk/xGqMemr7JkGPGemPrLLX7A== dependencies: "@next/env" "14.2.3" @@ -4622,51 +4622,51 @@ next@^14.2.3: node-fetch@^2.6.12: version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== node-releases@^2.0.14: version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" nwsapi@^2.2.2: version "2.2.10" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.10.tgz#0b77a68e21a0b483db70b11fad055906e867cda8" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.10.tgz" integrity sha512-QK0sRs7MKv0tKe1+5uZIQk/C8XGza4DAnztJG8iD+TpJIORARrCxczA738awHrZoHeTjSSoHqao2teO0dC/gFQ== object-assign@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-inspect@^1.13.1: version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== object-is@^1.1.5: version "1.1.6" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + resolved "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz" integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== dependencies: call-bind "^1.0.7" @@ -4674,12 +4674,12 @@ object-is@^1.1.5: object-keys@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== object.assign@^4.1.4, object.assign@^4.1.5: version "4.1.5" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz" integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: call-bind "^1.0.5" @@ -4689,7 +4689,7 @@ object.assign@^4.1.4, object.assign@^4.1.5: object.entries@^1.1.7: version "1.1.8" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41" + resolved "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz" integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ== dependencies: call-bind "^1.0.7" @@ -4698,7 +4698,7 @@ object.entries@^1.1.7: object.fromentries@^2.0.7: version "2.0.8" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz" integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: call-bind "^1.0.7" @@ -4708,7 +4708,7 @@ object.fromentries@^2.0.7: object.groupby@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + resolved "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz" integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== dependencies: call-bind "^1.0.7" @@ -4717,7 +4717,7 @@ object.groupby@^1.0.1: object.hasown@^1.1.3: version "1.1.4" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.4.tgz#e270ae377e4c120cdcb7656ce66884a6218283dc" + resolved "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz" integrity sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg== dependencies: define-properties "^1.2.1" @@ -4726,7 +4726,7 @@ object.hasown@^1.1.3: object.values@^1.1.6, object.values@^1.1.7: version "1.2.0" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz" integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== dependencies: call-bind "^1.0.7" @@ -4735,21 +4735,21 @@ object.values@^1.1.6, object.values@^1.1.7: once@^1.3.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" onetime@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" 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" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" @@ -4761,47 +4761,47 @@ optionator@^0.9.3: p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.0" p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" p-try@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" parse-json@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== dependencies: "@babel/code-frame" "^7.0.0" @@ -4811,34 +4811,34 @@ parse-json@^5.2.0: parse5@^7.0.0, parse5@^7.1.1: version "7.1.2" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz" integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== dependencies: entities "^4.4.0" path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-scurry@^1.10.1: version "1.11.1" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz" integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: lru-cache "^10.2.0" @@ -4846,44 +4846,44 @@ path-scurry@^1.10.1: path-type@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== picocolors@^1.0.0, picocolors@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pirates@^4.0.4: version "4.0.6" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== pkg-dir@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" possible-typed-array-names@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + resolved "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz" integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== postcss-value-parser@^4.0.2: version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== postcss@8.4.31: version "8.4.31" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: nanoid "^3.3.6" @@ -4892,7 +4892,7 @@ postcss@8.4.31: postcss@8.4.38: version "8.4.38" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz" integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== dependencies: nanoid "^3.3.7" @@ -4901,24 +4901,24 @@ postcss@8.4.38: prelude-ls@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prettier-linter-helpers@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + resolved "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz" integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== dependencies: fast-diff "^1.1.2" prettier@^3.2.5: version "3.2.5" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + resolved "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz" integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== pretty-format@^27.0.2: version "27.5.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz" integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== dependencies: ansi-regex "^5.0.1" @@ -4927,7 +4927,7 @@ pretty-format@^27.0.2: pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== dependencies: "@jest/schemas" "^29.6.3" @@ -4936,7 +4936,7 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: prompts@^2.0.1: version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" @@ -4944,7 +4944,7 @@ prompts@^2.0.1: prop-types@^15.8.1: version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== dependencies: loose-envify "^1.4.0" @@ -4953,42 +4953,42 @@ prop-types@^15.8.1: proxy-from-env@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== psl@^1.1.33: version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== punycode@^2.1.0, punycode@^2.1.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== pure-rand@^6.0.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz" integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== qrcode.react@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-3.1.0.tgz#5c91ddc0340f768316fbdb8fff2765134c2aecd8" + resolved "https://registry.npmjs.org/qrcode.react/-/qrcode.react-3.1.0.tgz" integrity sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q== querystringify@^2.1.1: version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== queue-microtask@^1.2.2: version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== rc-cascader@~3.26.0: version "3.26.0" - resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.26.0.tgz#1bcc9c29451047dc99e28fdd125c94828d7ddf76" + resolved "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.26.0.tgz" integrity sha512-L1dml383TPSJD1I11YwxuVbmqaJY64psZqFp1ETlgl3LEOwDu76Cyl11fw5dmjJhMlUWwM5dECQfqJgfebhUjg== dependencies: "@babel/runtime" "^7.12.5" @@ -5000,7 +5000,7 @@ rc-cascader@~3.26.0: rc-checkbox@~3.3.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/rc-checkbox/-/rc-checkbox-3.3.0.tgz#0ffcb65ab78c7d2fcd1a0d6554af36786516bd02" + resolved "https://registry.npmjs.org/rc-checkbox/-/rc-checkbox-3.3.0.tgz" integrity sha512-Ih3ZaAcoAiFKJjifzwsGiT/f/quIkxJoklW4yKGho14Olulwn8gN7hOBve0/WGDg5o/l/5mL0w7ff7/YGvefVw== dependencies: "@babel/runtime" "^7.10.1" @@ -5009,7 +5009,7 @@ rc-checkbox@~3.3.0: rc-collapse@~3.7.3: version "3.7.3" - resolved "https://registry.yarnpkg.com/rc-collapse/-/rc-collapse-3.7.3.tgz#68161683d8fd1004bef4eb281fc106f3c8dc16eb" + resolved "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.7.3.tgz" integrity sha512-60FJcdTRn0X5sELF18TANwtVi7FtModq649H11mYF1jh83DniMoM4MqY627sEKRCTm4+WXfGDcB7hY5oW6xhyw== dependencies: "@babel/runtime" "^7.10.1" @@ -5019,7 +5019,7 @@ rc-collapse@~3.7.3: rc-dialog@~9.4.0: version "9.4.0" - resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-9.4.0.tgz#194c107d34cb36a56f1db4a49dc73f6d59eeae85" + resolved "https://registry.npmjs.org/rc-dialog/-/rc-dialog-9.4.0.tgz" integrity sha512-AScCexaLACvf8KZRqCPz12BJ8olszXOS4lKlkMyzDQHS1m0zj1KZMYgmMCh39ee0Dcv8kyrj8mTqxuLyhH+QuQ== dependencies: "@babel/runtime" "^7.10.1" @@ -5030,7 +5030,7 @@ rc-dialog@~9.4.0: rc-drawer@~7.1.0: version "7.1.0" - resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-7.1.0.tgz#2beabb8bab1784aea255d0d850bc206c3dc715da" + resolved "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.1.0.tgz" integrity sha512-nBE1rF5iZvpavoyqhSSz2mk/yANltA7g3aF0U45xkx381n3we/RKs9cJfNKp9mSWCedOKWt9FLEwZDaAaOGn2w== dependencies: "@babel/runtime" "^7.23.9" @@ -5041,7 +5041,7 @@ rc-drawer@~7.1.0: rc-dropdown@~4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/rc-dropdown/-/rc-dropdown-4.2.0.tgz#c6052fcfe9c701487b141e411cdc277dc7c6f061" + resolved "https://registry.npmjs.org/rc-dropdown/-/rc-dropdown-4.2.0.tgz" integrity sha512-odM8Ove+gSh0zU27DUj5cG1gNKg7mLWBYzB5E4nNLrLwBmYEgYP43vHKDGOVZcJSVElQBI0+jTQgjnq0NfLjng== dependencies: "@babel/runtime" "^7.18.3" @@ -5051,7 +5051,7 @@ rc-dropdown@~4.2.0: rc-field-form@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-2.0.1.tgz#97dc352f3899e9617f2abfd0c09bf0fcd17409e2" + resolved "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.0.1.tgz" integrity sha512-3WK/POHBcfMFKrzScrkmgMIXqoVQ0KgVwcVnej/ukwuQG4ZHCJaTi2KhM+tWTK4WODBXbmjKg5pKHj2IVmSg4A== dependencies: "@babel/runtime" "^7.18.0" @@ -5060,7 +5060,7 @@ rc-field-form@~2.0.1: rc-image@~7.6.0: version "7.6.0" - resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-7.6.0.tgz#2867087b77c8595ea9eb37d18ca863e47904b191" + resolved "https://registry.npmjs.org/rc-image/-/rc-image-7.6.0.tgz" integrity sha512-tL3Rvd1sS+frZQ01i+tkeUPaOeFz2iG9/scAt/Cfs0hyCRVA/w0Pu1J/JxIX8blalvmHE0bZQRYdOmRAzWu4Hg== dependencies: "@babel/runtime" "^7.11.2" @@ -5072,7 +5072,7 @@ rc-image@~7.6.0: rc-input-number@~9.1.0: version "9.1.0" - resolved "https://registry.yarnpkg.com/rc-input-number/-/rc-input-number-9.1.0.tgz#fd577db284b65548c156500322a2feaa04321565" + resolved "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.1.0.tgz" integrity sha512-NqJ6i25Xn/AgYfVxynlevIhX3FuKlMwIFpucGG1h98SlK32wQwDK0zhN9VY32McOmuaqzftduNYWWooWz8pXQA== dependencies: "@babel/runtime" "^7.10.1" @@ -5083,7 +5083,7 @@ rc-input-number@~9.1.0: rc-input@~1.5.0: version "1.5.1" - resolved "https://registry.yarnpkg.com/rc-input/-/rc-input-1.5.1.tgz#36d37eb045f1fa17de7da1a3fab94edfa331ab92" + resolved "https://registry.npmjs.org/rc-input/-/rc-input-1.5.1.tgz" integrity sha512-+nOzQJDeIfIpNP/SgY45LXSKbuMlp4Yap2y8c+ZpU7XbLmNzUd6+d5/S75sA/52jsVE6S/AkhkkDEAOjIu7i6g== dependencies: "@babel/runtime" "^7.11.1" @@ -5092,7 +5092,7 @@ rc-input@~1.5.0: rc-mentions@~2.13.1: version "2.13.1" - resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-2.13.1.tgz#14586ffa4a1ddd4079564f38abf2b4351671feca" + resolved "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.13.1.tgz" integrity sha512-DSyUDq/PPCleUX1eghIn371lTSRQsIuCs1N7xR9nZcHP9R1NkE7JjpWUP8Gy4EGVPu0JN0qIcokxYJaoGPnofg== dependencies: "@babel/runtime" "^7.22.5" @@ -5105,7 +5105,7 @@ rc-mentions@~2.13.1: rc-menu@~9.14.0: version "9.14.0" - resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-9.14.0.tgz#5e072cfc731a6dd95005d4247f02543679b0836b" + resolved "https://registry.npmjs.org/rc-menu/-/rc-menu-9.14.0.tgz" integrity sha512-La3LBCDMLMs9Q/8mTGbnscb+ZeJ26ebkLz9xJFHd2SD8vfsCKl1Z/k3mwbxyKL01lB40fel1s9Nn9LAv/nmVJQ== dependencies: "@babel/runtime" "^7.10.1" @@ -5117,7 +5117,7 @@ rc-menu@~9.14.0: rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motion@^2.4.3, rc-motion@^2.4.4, rc-motion@^2.6.1, rc-motion@^2.6.2, rc-motion@^2.9.0, rc-motion@^2.9.1: version "2.9.1" - resolved "https://registry.yarnpkg.com/rc-motion/-/rc-motion-2.9.1.tgz#5b405437f9f673ed1a59b6b797c2227c2d6b3d91" + resolved "https://registry.npmjs.org/rc-motion/-/rc-motion-2.9.1.tgz" integrity sha512-QD4bUqByjVQs7PhUT1d4bNxvtTcK9ETwtg7psbDfo6TmYalH/1hhjj4r2hbhW7g5OOEqYHhfwfj4noIvuOVRtQ== dependencies: "@babel/runtime" "^7.11.1" @@ -5126,7 +5126,7 @@ rc-motion@^2.0.0, rc-motion@^2.0.1, rc-motion@^2.3.0, rc-motion@^2.3.4, rc-motio rc-notification@~5.4.0: version "5.4.0" - resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-5.4.0.tgz#c5ea20bfe4ed2dbacc7ef945777626c050945db8" + resolved "https://registry.npmjs.org/rc-notification/-/rc-notification-5.4.0.tgz" integrity sha512-li19y9RoYJciF3WRFvD+DvWS70jdL8Fr+Gfb/OshK+iY6iTkwzoigmSIp76/kWh5tF5i/i9im12X3nsF85GYdA== dependencies: "@babel/runtime" "^7.10.1" @@ -5136,7 +5136,7 @@ rc-notification@~5.4.0: rc-overflow@^1.3.1, rc-overflow@^1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/rc-overflow/-/rc-overflow-1.3.2.tgz#72ee49e85a1308d8d4e3bd53285dc1f3e0bcce2c" + resolved "https://registry.npmjs.org/rc-overflow/-/rc-overflow-1.3.2.tgz" integrity sha512-nsUm78jkYAoPygDAcGZeC2VwIg/IBGSodtOY3pMof4W3M9qRJgqaDYm03ZayHlde3I6ipliAxbN0RUcGf5KOzw== dependencies: "@babel/runtime" "^7.11.1" @@ -5146,7 +5146,7 @@ rc-overflow@^1.3.1, rc-overflow@^1.3.2: rc-pagination@~4.0.4: version "4.0.4" - resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-4.0.4.tgz#ea401388ae86eac17ed5b41212d487f12b65b773" + resolved "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.0.4.tgz" integrity sha512-GGrLT4NgG6wgJpT/hHIpL9nELv27A1XbSZzECIuQBQTVSf4xGKxWr6I/jhpRPauYEWEbWVw22ObG6tJQqwJqWQ== dependencies: "@babel/runtime" "^7.10.1" @@ -5155,7 +5155,7 @@ rc-pagination@~4.0.4: rc-picker@~4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-4.5.0.tgz#ae7a028ed6184e0ef40a2c8aaeb9d5dbef89d4b8" + resolved "https://registry.npmjs.org/rc-picker/-/rc-picker-4.5.0.tgz" integrity sha512-suqz9bzuhBQlf7u+bZd1bJLPzhXpk12w6AjQ9BTPTiFwexVZgUKViG1KNLyfFvW6tCUZZK0HmCCX7JAyM+JnCg== dependencies: "@babel/runtime" "^7.10.1" @@ -5167,7 +5167,7 @@ rc-picker@~4.5.0: rc-progress@~4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-4.0.0.tgz#5382147d9add33d3a5fbd264001373df6440e126" + resolved "https://registry.npmjs.org/rc-progress/-/rc-progress-4.0.0.tgz" integrity sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw== dependencies: "@babel/runtime" "^7.10.1" @@ -5176,7 +5176,7 @@ rc-progress@~4.0.0: rc-rate@~2.12.0: version "2.12.0" - resolved "https://registry.yarnpkg.com/rc-rate/-/rc-rate-2.12.0.tgz#0182deffed3b009cdcc61660da8746c39ed91ed5" + resolved "https://registry.npmjs.org/rc-rate/-/rc-rate-2.12.0.tgz" integrity sha512-g092v5iZCdVzbjdn28FzvWebK2IutoVoiTeqoLTj9WM7SjA/gOJIw5/JFZMRyJYYVe1jLAU2UhAfstIpCNRozg== dependencies: "@babel/runtime" "^7.10.1" @@ -5185,7 +5185,7 @@ rc-rate@~2.12.0: rc-resize-observer@^1.0.0, rc-resize-observer@^1.1.0, rc-resize-observer@^1.3.1, rc-resize-observer@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz#7bba61e6b3c604834980647cce6451914750d0cc" + resolved "https://registry.npmjs.org/rc-resize-observer/-/rc-resize-observer-1.4.0.tgz" integrity sha512-PnMVyRid9JLxFavTjeDXEXo65HCRqbmLBw9xX9gfC4BZiSzbLXKzW3jPz+J0P71pLbD5tBMTT+mkstV5gD0c9Q== dependencies: "@babel/runtime" "^7.20.7" @@ -5195,7 +5195,7 @@ rc-resize-observer@^1.0.0, rc-resize-observer@^1.1.0, rc-resize-observer@^1.3.1, rc-segmented@~2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/rc-segmented/-/rc-segmented-2.3.0.tgz#b3fe080fb434a266c02e30bb62a47d2c6e094341" + resolved "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.3.0.tgz" integrity sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg== dependencies: "@babel/runtime" "^7.11.1" @@ -5205,7 +5205,7 @@ rc-segmented@~2.3.0: rc-select@~14.14.0: version "14.14.0" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-14.14.0.tgz#110771fad72496843b245236bcb0007553b9fe0d" + resolved "https://registry.npmjs.org/rc-select/-/rc-select-14.14.0.tgz" integrity sha512-Uo2wulrjoPPRLCPd7zlK4ZFVJxlTN//yp1xWP/U+TUOQCyXrT+Duvq/Si5OzVcmQyWAUSbsplc2OwNNhvbOeKQ== dependencies: "@babel/runtime" "^7.10.1" @@ -5218,7 +5218,7 @@ rc-select@~14.14.0: rc-slider@~10.6.2: version "10.6.2" - resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-10.6.2.tgz#8bd3b63b24f2f3682ea1bf86d021073189cf33eb" + resolved "https://registry.npmjs.org/rc-slider/-/rc-slider-10.6.2.tgz" integrity sha512-FjkoFjyvUQWcBo1F3RgSglky3ar0+qHLM41PlFVYB4Bj3RD8E/Mv7kqMouLFBU+3aFglMzzctAIWRwajEuueSw== dependencies: "@babel/runtime" "^7.10.1" @@ -5227,7 +5227,7 @@ rc-slider@~10.6.2: rc-steps@~6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/rc-steps/-/rc-steps-6.0.1.tgz#c2136cd0087733f6d509209a84a5c80dc29a274d" + resolved "https://registry.npmjs.org/rc-steps/-/rc-steps-6.0.1.tgz" integrity sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g== dependencies: "@babel/runtime" "^7.16.7" @@ -5236,7 +5236,7 @@ rc-steps@~6.0.1: rc-switch@~4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/rc-switch/-/rc-switch-4.1.0.tgz#f37d81b4e0c5afd1274fd85367b17306bf25e7d7" + resolved "https://registry.npmjs.org/rc-switch/-/rc-switch-4.1.0.tgz" integrity sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg== dependencies: "@babel/runtime" "^7.21.0" @@ -5245,7 +5245,7 @@ rc-switch@~4.1.0: rc-table@~7.45.6: version "7.45.6" - resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.45.6.tgz#53286fc08cd18f0be704de76fdbf19d1de7749da" + resolved "https://registry.npmjs.org/rc-table/-/rc-table-7.45.6.tgz" integrity sha512-FYsTya3RQzLYct+o3fqHIZQIwrmsvrvhTg/I6hzlJZ1XoVAGoTmgkN1mMilVlYgksZTey9BCNYh94c6yhdjTXQ== dependencies: "@babel/runtime" "^7.10.1" @@ -5257,7 +5257,7 @@ rc-table@~7.45.6: rc-tabs@~15.1.0: version "15.1.0" - resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-15.1.0.tgz#6f6addf3ec4d0815f9f05d1317b47a579838e92f" + resolved "https://registry.npmjs.org/rc-tabs/-/rc-tabs-15.1.0.tgz" integrity sha512-xTNz4Km1025emtkv1q7xKhjPwAtXr/wycuXVTAcFJg+DKhnPDDbnwbA9KRW0SawAVOGvVEj8ZrBlU0u0FGLrbg== dependencies: "@babel/runtime" "^7.11.2" @@ -5270,7 +5270,7 @@ rc-tabs@~15.1.0: rc-textarea@~1.7.0: version "1.7.0" - resolved "https://registry.yarnpkg.com/rc-textarea/-/rc-textarea-1.7.0.tgz#115c421359dddee58c601008ec2209b41cb8f8df" + resolved "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.7.0.tgz" integrity sha512-UxizYJkWkmxP3zofXgc487QiGyDmhhheDLLjIWbFtDmiru1ls30KpO8odDaPyqNUIy9ugj5djxTEuezIn6t3Jg== dependencies: "@babel/runtime" "^7.10.1" @@ -5281,7 +5281,7 @@ rc-textarea@~1.7.0: rc-tooltip@~6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-6.2.0.tgz#4dd7575674137a5b14f118a5c16435d3f5e4a9c9" + resolved "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.2.0.tgz" integrity sha512-iS/3iOAvtDh9GIx1ulY7EFUXUtktFccNLsARo3NPgLf0QW9oT0w3dA9cYWlhqAKmD+uriEwdWz1kH0Qs4zk2Aw== dependencies: "@babel/runtime" "^7.11.2" @@ -5290,7 +5290,7 @@ rc-tooltip@~6.2.0: rc-tree-select@~5.21.0: version "5.21.0" - resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-5.21.0.tgz#4ff94d5c28cba9810c4970d1f12ab7248c3b6e55" + resolved "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.21.0.tgz" integrity sha512-w+9qEu6zh0G3wt9N/hzWNSnqYH1i9mH1Nqxo0caxLRRFXF5yZWYmpCDoDTMdQM1Y4z3Q5yj08qyrPH/d4AtumA== dependencies: "@babel/runtime" "^7.10.1" @@ -5301,7 +5301,7 @@ rc-tree-select@~5.21.0: rc-tree@~5.8.1, rc-tree@~5.8.7: version "5.8.7" - resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-5.8.7.tgz#79fe560eca8a998a5cd866cdf374ffc3643754f1" + resolved "https://registry.npmjs.org/rc-tree/-/rc-tree-5.8.7.tgz" integrity sha512-cpsIQZ4nNYwpj6cqPRt52e/69URuNdgQF9wZ10InmEf8W3+i0A41OVmZWwHuX9gegQSqj+DPmaDkZFKQZ+ZV1w== dependencies: "@babel/runtime" "^7.10.1" @@ -5312,7 +5312,7 @@ rc-tree@~5.8.1, rc-tree@~5.8.7: rc-upload@~4.5.2: version "4.5.2" - resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-4.5.2.tgz#ea493fbaaf57d9369ee954b20e1d8bc35c818a1a" + resolved "https://registry.npmjs.org/rc-upload/-/rc-upload-4.5.2.tgz" integrity sha512-QO3ne77DwnAPKFn0bA5qJM81QBjQi0e0NHdkvpFyY73Bea2NfITiotqJqVjHgeYPOJu5lLVR32TNGP084aSoXA== dependencies: "@babel/runtime" "^7.18.3" @@ -5321,7 +5321,7 @@ rc-upload@~4.5.2: rc-util@^5.0.1, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.2.0, rc-util@^5.20.1, rc-util@^5.21.0, rc-util@^5.24.4, rc-util@^5.25.2, rc-util@^5.27.0, rc-util@^5.30.0, rc-util@^5.31.1, rc-util@^5.32.2, rc-util@^5.34.1, rc-util@^5.35.0, rc-util@^5.36.0, rc-util@^5.37.0, rc-util@^5.38.0, rc-util@^5.38.1, rc-util@^5.39.3, rc-util@^5.40.1: version "5.41.0" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.41.0.tgz#b1ba000d4f3a9e72563370a3243b59f89b40e1bd" + resolved "https://registry.npmjs.org/rc-util/-/rc-util-5.41.0.tgz" integrity sha512-xtlCim9RpmVv0Ar2Nnc3WfJCxjQkTf3xHPWoFdjp1fSs2NirQwqiQrfqdU9HUe0kdfb168M/T8Dq0IaX50xeKg== dependencies: "@babel/runtime" "^7.18.3" @@ -5329,7 +5329,7 @@ rc-util@^5.0.1, rc-util@^5.16.1, rc-util@^5.17.0, rc-util@^5.18.1, rc-util@^5.2. rc-virtual-list@^3.11.1, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2: version "3.14.2" - resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.14.2.tgz#8ffee57100eab1eeae8df6a67bf75d0b7fd176cc" + resolved "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.14.2.tgz" integrity sha512-rA+W5xryhklJAcmswNyuKB3ZGeB855io+yOFQK5u/RXhjdshGblfKpNkQr4/9fBhZns0+uiL/0/s6IP2krtSmg== dependencies: "@babel/runtime" "^7.20.0" @@ -5339,7 +5339,7 @@ rc-virtual-list@^3.11.1, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2: react-canvas-confetti@1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/react-canvas-confetti/-/react-canvas-confetti-1.2.1.tgz#22ac64cbc478cf57cb5f61c130322e359b35389d" + resolved "https://registry.npmjs.org/react-canvas-confetti/-/react-canvas-confetti-1.2.1.tgz" integrity sha512-onNjQNkhQjrB2JVCeRpJW7o8VlBNJvo3Eht9zlQlofNLVvvOd1+PzBLU5Ev8n5sFBkTbKJmIUVG0eZnkAl5cpg== dependencies: "@types/canvas-confetti" "1.4.0" @@ -5347,7 +5347,7 @@ react-canvas-confetti@1.2.1: react-dom@^18.3.1: version "18.3.1" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz" integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw== dependencies: loose-envify "^1.1.0" @@ -5355,36 +5355,36 @@ react-dom@^18.3.1: react-is@^16.13.1: version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== react-is@^17.0.1: version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + resolved "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== react-is@^18.0.0, react-is@^18.2.0: version "18.3.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== react@^18.3.1: version "18.3.1" - resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891" + resolved "https://registry.npmjs.org/react/-/react-18.3.1.tgz" integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ== dependencies: loose-envify "^1.1.0" readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" redent@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + resolved "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz" integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== dependencies: indent-string "^4.0.0" @@ -5392,7 +5392,7 @@ redent@^3.0.0: reflect.getprototypeof@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz#3ab04c32a8390b770712b7a8633972702d278859" + resolved "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz" integrity sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg== dependencies: call-bind "^1.0.7" @@ -5405,12 +5405,12 @@ reflect.getprototypeof@^1.0.4: regenerator-runtime@^0.14.0: version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: version "1.5.2" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz#138f644a3350f981a858c44f6bb1a61ff59be334" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz" integrity sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw== dependencies: call-bind "^1.0.6" @@ -5420,49 +5420,49 @@ regexp.prototype.flags@^1.5.1, regexp.prototype.flags@^1.5.2: require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== resize-observer-polyfill@^1.5.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + resolved "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz" integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: resolve-from "^5.0.0" resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve-pkg-maps@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== resolve.exports@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.20.0, resolve@^1.22.4: version "1.22.8" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: is-core-module "^2.13.0" @@ -5471,7 +5471,7 @@ resolve@^1.20.0, resolve@^1.22.4: resolve@^2.0.0-next.5: version "2.0.0-next.5" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz" integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== dependencies: is-core-module "^2.13.0" @@ -5480,26 +5480,26 @@ resolve@^2.0.0-next.5: reusify@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rimraf@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" run-parallel@^1.1.9: version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: queue-microtask "^1.2.2" safe-array-concat@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz" integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== dependencies: call-bind "^1.0.7" @@ -5509,7 +5509,7 @@ safe-array-concat@^1.1.2: safe-regex-test@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz" integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== dependencies: call-bind "^1.0.6" @@ -5518,12 +5518,12 @@ safe-regex-test@^1.0.3: "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sass@^1.72.0: version "1.77.2" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.77.2.tgz#18d4ed2eefc260cdc8099c5439ec1303fd5863aa" + resolved "https://registry.npmjs.org/sass/-/sass-1.77.2.tgz" integrity sha512-eb4GZt1C3avsX3heBNlrc7I09nyT00IUuo4eFhAbeXWU2fvA7oXI53SxODVAA+zgZCk9aunAZgO+losjR3fAwA== dependencies: chokidar ">=3.0.0 <4.0.0" @@ -5532,48 +5532,43 @@ sass@^1.72.0: saxes@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + resolved "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz" integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== dependencies: xmlchars "^2.2.0" scheduler@^0.23.2: version "0.23.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz" integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ== dependencies: loose-envify "^1.1.0" scroll-into-view-if-needed@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz#fa9524518c799b45a2ef6bbffb92bcad0296d01f" + resolved "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz" integrity sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ== dependencies: compute-scroll-into-view "^3.0.2" scrypt-js@3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== semver@^6.3.0, semver@^6.3.1: version "6.3.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.7, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: - version "7.6.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13" - integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== - -semver@^7.6.3: +semver@^7.3.7, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: version "7.6.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== set-function-length@^1.2.1: version "1.2.2" - resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== dependencies: define-data-property "^1.1.4" @@ -5585,7 +5580,7 @@ set-function-length@^1.2.1: set-function-name@^2.0.1, set-function-name@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + resolved "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz" integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== dependencies: define-data-property "^1.1.4" @@ -5595,24 +5590,24 @@ set-function-name@^2.0.1, set-function-name@^2.0.2: shallowequal@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + resolved "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== side-channel@^1.0.4, side-channel@^1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== dependencies: call-bind "^1.0.7" @@ -5622,32 +5617,32 @@ side-channel@^1.0.4, side-channel@^1.0.6: signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== signal-exit@^4.0.1: version "4.1.0" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== sisteransi@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz" integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== source-map-support@0.5.13: version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" @@ -5655,41 +5650,41 @@ source-map-support@0.5.13: source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== stack-utils@^2.0.3: version "2.0.6" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== dependencies: escape-string-regexp "^2.0.0" stop-iteration-iterator@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" + resolved "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz" integrity sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ== dependencies: internal-slot "^1.0.4" streamsearch@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" + resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== string-convert@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" + resolved "https://registry.npmjs.org/string-convert/-/string-convert-0.2.1.tgz" integrity sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A== string-length@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: char-regex "^1.0.2" @@ -5697,7 +5692,7 @@ string-length@^4.0.1: "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" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -5706,7 +5701,7 @@ string-length@^4.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" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -5715,7 +5710,7 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: eastasianwidth "^0.2.0" @@ -5724,7 +5719,7 @@ string-width@^5.0.1, string-width@^5.1.2: string.prototype.matchall@^4.0.10: version "4.0.11" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a" + resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz" integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg== dependencies: call-bind "^1.0.7" @@ -5742,7 +5737,7 @@ string.prototype.matchall@^4.0.10: string.prototype.trim@^1.2.9: version "1.2.9" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz" integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: call-bind "^1.0.7" @@ -5752,7 +5747,7 @@ string.prototype.trim@^1.2.9: string.prototype.trimend@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz" integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: call-bind "^1.0.7" @@ -5761,7 +5756,7 @@ string.prototype.trimend@^1.0.8: string.prototype.trimstart@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz" integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== dependencies: call-bind "^1.0.7" @@ -5770,55 +5765,55 @@ string.prototype.trimstart@^1.0.8: "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" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" 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" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-ansi@^7.0.1: version "7.1.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== dependencies: ansi-regex "^6.0.1" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== strip-bom@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== strip-indent@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz" integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== dependencies: min-indent "^1.0.0" strip-json-comments@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== styled-components@^6.1.8: version "6.1.11" - resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-6.1.11.tgz#01948e5195bf1d39e57e0a85b41958c80e40cfb8" + resolved "https://registry.npmjs.org/styled-components/-/styled-components-6.1.11.tgz" integrity sha512-Ui0jXPzbp1phYij90h12ksljKGqF8ncGx+pjrNPsSPhbUUjWT2tD1FwGo2LF6USCnbrsIhNngDfodhxbegfEOA== dependencies: "@emotion/is-prop-valid" "1.2.2" @@ -5833,50 +5828,50 @@ styled-components@^6.1.8: styled-jsx@5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f" + resolved "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz" integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw== dependencies: client-only "0.0.1" stylis@4.3.2, stylis@^4.0.13: version "4.3.2" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.2.tgz#8f76b70777dd53eb669c6f58c997bf0a9972e444" + resolved "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz" integrity sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg== supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" supports-color@^8.0.0: version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== dependencies: has-flag "^4.0.0" supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== symbol-tree@^3.2.4: version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== synckit@^0.8.6: version "0.8.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" + resolved "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz" integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== dependencies: "@pkgr/core" "^0.1.0" @@ -5884,12 +5879,12 @@ synckit@^0.8.6: tapable@^2.2.0: version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" @@ -5898,39 +5893,39 @@ test-exclude@^6.0.0: text-table@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== throttle-debounce@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-5.0.0.tgz#a17a4039e82a2ed38a5e7268e4132d6960d41933" + resolved "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-5.0.0.tgz" integrity sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg== tmpl@1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" toggle-selection@^1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + resolved "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz" integrity sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ== tough-cookie@^4.1.2: version "4.1.4" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz" integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== dependencies: psl "^1.1.33" @@ -5940,24 +5935,24 @@ tough-cookie@^4.1.2: tr46@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + resolved "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz" integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== dependencies: punycode "^2.1.1" tr46@~0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== ts-api-utils@^1.0.1, ts-api-utils@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== ts-node@^10.9.2: version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" @@ -5976,7 +5971,7 @@ ts-node@^10.9.2: tsconfig-paths@^3.15.0: version "3.15.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz" integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== dependencies: "@types/json5" "^0.0.29" @@ -5986,46 +5981,46 @@ tsconfig-paths@^3.15.0: tslib@2.6.2, tslib@^2.4.0, tslib@^2.6.2: version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== tslib@^1.8.1: version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== tsutils@^3.21.0: version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== dependencies: tslib "^1.8.1" type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== dependencies: prelude-ls "^1.2.1" type-detect@4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-fest@^0.20.2: version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== typed-array-buffer@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz" integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: call-bind "^1.0.7" @@ -6034,7 +6029,7 @@ typed-array-buffer@^1.0.2: typed-array-byte-length@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + resolved "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz" integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== dependencies: call-bind "^1.0.7" @@ -6045,7 +6040,7 @@ typed-array-byte-length@^1.0.1: typed-array-byte-offset@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + resolved "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz" integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== dependencies: available-typed-arrays "^1.0.7" @@ -6057,7 +6052,7 @@ typed-array-byte-offset@^1.0.2: typed-array-length@^1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz" integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== dependencies: call-bind "^1.0.7" @@ -6067,14 +6062,14 @@ typed-array-length@^1.0.6: is-typed-array "^1.1.13" possible-typed-array-names "^1.0.0" -typescript@5.5.3: - version "5.5.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa" - integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ== +typescript@5.3.x: + version "5.3.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz" + integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== unbox-primitive@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== dependencies: call-bind "^1.0.2" @@ -6084,17 +6079,17 @@ unbox-primitive@^1.0.2: undici-types@~5.26.4: version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== universalify@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== update-browserslist-db@^1.0.13: version "1.0.16" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz#f6d489ed90fb2f07d67784eb3f53d7891f736356" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz" integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== dependencies: escalade "^3.1.2" @@ -6102,14 +6097,14 @@ update-browserslist-db@^1.0.13: uri-js@^4.2.2: version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" url-parse@^1.5.3: version "1.5.10" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== dependencies: querystringify "^2.1.1" @@ -6117,19 +6112,19 @@ url-parse@^1.5.3: usehooks-ts@^2.14.0: version "2.16.0" - resolved "https://registry.yarnpkg.com/usehooks-ts/-/usehooks-ts-2.16.0.tgz#31deaa2f1147f65666aae925bd890b54e63b0d3f" + resolved "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-2.16.0.tgz" integrity sha512-bez95WqYujxp6hFdM/CpRDiVPirZPxlMzOH2QB8yopoKQMXpscyZoxOjpEdaxvV+CAWUDSM62cWnqHE0E/MZ7w== dependencies: lodash.debounce "^4.0.8" v8-compile-cache-lib@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== v8-to-istanbul@^9.0.1: version "9.2.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz" integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" @@ -6138,43 +6133,43 @@ v8-to-istanbul@^9.0.1: w3c-xmlserializer@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz" integrity sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw== dependencies: xml-name-validator "^4.0.0" walker@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: makeerror "1.0.12" webidl-conversions@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== webidl-conversions@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== whatwg-encoding@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz" integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== dependencies: iconv-lite "0.6.3" whatwg-mimetype@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz" integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== whatwg-url@^11.0.0: version "11.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz" integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== dependencies: tr46 "^3.0.0" @@ -6182,7 +6177,7 @@ whatwg-url@^11.0.0: whatwg-url@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" @@ -6190,7 +6185,7 @@ whatwg-url@^5.0.0: which-boxed-primitive@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: is-bigint "^1.0.1" @@ -6201,7 +6196,7 @@ which-boxed-primitive@^1.0.2: which-builtin-type@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.1.3.tgz#b1b8443707cc58b6e9bf98d32110ff0c2cbd029b" + resolved "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz" integrity sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw== dependencies: function.prototype.name "^1.1.5" @@ -6219,7 +6214,7 @@ which-builtin-type@^1.1.3: which-collection@^1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + resolved "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz" integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== dependencies: is-map "^2.0.3" @@ -6229,7 +6224,7 @@ which-collection@^1.0.1: which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9: version "1.1.15" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz" integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: available-typed-arrays "^1.0.7" @@ -6240,19 +6235,19 @@ which-typed-array@^1.1.13, which-typed-array@^1.1.14, which-typed-array@^1.1.15, which@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" word-wrap@^1.2.5: version "1.2.5" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== "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" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -6261,7 +6256,7 @@ word-wrap@^1.2.5: wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -6270,7 +6265,7 @@ wrap-ansi@^7.0.0: wrap-ansi@^8.1.0: version "8.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== dependencies: ansi-styles "^6.1.0" @@ -6279,12 +6274,12 @@ wrap-ansi@^8.1.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^4.0.2: version "4.0.2" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== dependencies: imurmurhash "^0.1.4" @@ -6292,42 +6287,42 @@ write-file-atomic@^4.0.2: ws@7.4.6: version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== ws@^8.11.0: version "8.17.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.0.tgz#d145d18eca2ed25aaf791a183903f7be5e295fea" + resolved "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz" integrity sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow== xml-name-validator@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz" integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== xmlchars@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== y18n@^5.0.5: version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yallist@^3.0.2: version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yargs-parser@^21.1.1: version "21.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== yargs@^17.3.1: version "17.7.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" @@ -6340,15 +6335,15 @@ yargs@^17.3.1: yn@3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zod@^3.23.8: version "3.23.8" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" + resolved "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz" integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== diff --git a/package.json b/package.json index e80278bab..785cb7079 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "semver": "^7.6.3", "styled-components": "^6.1.8", "sudo-prompt": "9.2.1", + "typescript": "5.3.x", "usehooks-ts": "^2.14.0", "winston": "^3.13.0", "zod": "^3.23.8" @@ -63,5 +64,11 @@ "download-binaries": "sh download_binaries.sh", "build:pearl": "sh build_pearl.sh" }, - "version": "0.1.0-rc196" + "version": "0.1.0-rc196", + "engines": { + "node": ">=20", + "yarn": ">=1.22.0", + "npm": "please-use-yarn" + }, + "engineStrict": true } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 02de768fb..684a3fb4f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5812,6 +5812,11 @@ type-fest@^2.17.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== +typescript@5.3.x: + version "5.3.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" + integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== + typescript@^5.4.3: version "5.6.3" resolved "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" From a3d9b0fdf5eafc85139c0a557d84380675fb7daf Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Sat, 23 Nov 2024 22:18:28 +0000 Subject: [PATCH 382/463] refactor: remove unused chain-related logic and clean up ServicesProvider --- frontend/context/ServicesProvider.tsx | 99 +++++++++++++-------------- 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 4232eb4e2..694542f2b 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -15,7 +15,6 @@ import { AGENT_CONFIG } from '@/config/agents'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { AgentType } from '@/enums/Agent'; -import { EvmChainId } from '@/enums/Chain'; import { AgentEoa, AgentSafe, @@ -28,21 +27,21 @@ import { ServicesService } from '@/service/Services'; import { AgentConfig } from '@/types/Agent'; import { Service } from '@/types/Service'; import { Maybe } from '@/types/Util'; -import { asEvmChainId, asMiddlewareChain } from '@/utils/middlewareHelpers'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; import { OnlineStatusContext } from './OnlineStatusProvider'; type ServicesContextType = { services?: MiddlewareServiceResponse[]; serviceWallets?: AgentWallets; - servicesByMiddlewareChain?: Record< - string | MiddlewareChain, - MiddlewareServiceResponse[] - >; - servicesByEvmChainId?: Record< - number | EvmChainId, - MiddlewareServiceResponse[] - >; + // servicesByMiddlewareChain?: Record< + // string | MiddlewareChain, + // MiddlewareServiceResponse[] + // >; + // servicesByEvmChainId?: Record< + // number | EvmChainId, + // MiddlewareServiceResponse[] + // >; selectService: (serviceUuid: string) => void; selectedService?: Service; selectedAgentConfig: AgentConfig; @@ -115,39 +114,37 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { return config; }, [selectedAgentType]); - const servicesByMiddlewareChain = useMemo(() => { - if (!isFetched) return; - if (!services) return; - return Object.keys(EvmChainId).reduce< - Record<string | MiddlewareChain, MiddlewareServiceResponse[]> - >((acc, evmChainIdKey) => { - const middlewareChain = asMiddlewareChain( - EvmChainId[evmChainIdKey as keyof typeof EvmChainId], - ); - - acc[middlewareChain] = services.filter( - (service: MiddlewareServiceResponse) => - service.chain_configs[middlewareChain], - ); - return acc; - }, {}); - }, [isFetched, services]); - - const servicesByEvmChainId = useMemo(() => { - if (!isFetched) return; - if (!services) return; - return Object.keys(EvmChainId).reduce< - Record<number, MiddlewareServiceResponse[]> - >((acc, evmChainIdKey) => { - const evmChainId = EvmChainId[evmChainIdKey as keyof typeof EvmChainId]; - - acc[evmChainId] = services.filter( - (service: MiddlewareServiceResponse) => - service.chain_configs[asMiddlewareChain(evmChainId)], - ); - return acc; - }, {}); - }, [isFetched, services]); + // const servicesByHomeMiddlewareChain = useMemo(() => { + // if (!isFetched) return; + // if (!services) return; + // return services.reduce< + // Record<string | MiddlewareChain, MiddlewareServiceResponse[]> + // >((acc, service) => { + // if (!acc[service.home_chain]) { + // acc[service.home_chain] = [service.chain_configs[]]; + // return acc; + // } + + // acc[service.home_chain].push(service); + // return acc; + // }, {}); + // }, [isFetched, services]); + + // const servicesByHomeEvmChainId = useMemo(() => { + // if (!isFetched) return; + // if (!services) return; + // return Object.keys(EvmChainId).reduce< + // Record<number, MiddlewareServiceResponse[]> + // >((acc, evmChainIdKey) => { + // const evmChainId = EvmChainId[evmChainIdKey as keyof typeof EvmChainId]; + + // acc[evmChainId] = services.filter( + // (service: MiddlewareServiceResponse) => + // service.chain_configs[asMiddlewareChain(evmChainId)], + // ); + // return acc; + // }, {}); + // }, [isFetched, services]); const serviceAddresses = useMemo(() => { if (!isFetched) return; @@ -158,13 +155,9 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { return [ ...acc, ...Object.keys(service.chain_configs).reduce( - (acc: AgentWallets, middlewareChainKey: string) => { - const middlewareChain = - MiddlewareChain[ - middlewareChainKey as keyof typeof MiddlewareChain - ]; - - const chainConfig = service.chain_configs[middlewareChain]; + (acc: AgentWallets, middlewareChain: string) => { + const chainConfig = + service.chain_configs[middlewareChain as MiddlewareChain]; if (!chainConfig) return acc; @@ -189,7 +182,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { address: multisig, type: WalletType.Safe, owner: WalletOwnerType.Agent, - evmChainId: asEvmChainId(middlewareChainKey), + evmChainId: asEvmChainId(middlewareChain), } as AgentSafe); } @@ -225,8 +218,8 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { value={{ services, serviceWallets: serviceAddresses, - servicesByMiddlewareChain, - servicesByEvmChainId, + // servicesByMiddlewareChain: servicesByHomeMiddlewareChain, + // servicesByEvmChainId: servicesByHomeEvmChainId, isError, isFetched, isLoading, From f4d47a63d9dda2f8592ea9d67a52cb5e1f44c8db Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Sun, 24 Nov 2024 17:19:09 +0000 Subject: [PATCH 383/463] fix: use ledger_type not chain --- frontend/service/Wallet.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index 35fb2a8c0..857fcfee3 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -17,7 +17,7 @@ const createEoa = async (chain: MiddlewareChain) => headers: { ...CONTENT_TYPE_JSON_UTF8, }, - body: JSON.stringify({ chain }), + body: JSON.stringify({ ledger_type: 'ethereum' }), }).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to create EOA'); From 637bcc0388baaad0ffa994899dfee02373257e95 Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Sun, 24 Nov 2024 17:19:28 +0000 Subject: [PATCH 384/463] refactor: remove chain parameter from createEoa function --- frontend/service/Wallet.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index 857fcfee3..b8a29704b 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -11,7 +11,7 @@ const getWallets = async () => throw new Error('Failed to get wallets'); }) as Promise<MiddlewareWalletResponse>; -const createEoa = async (chain: MiddlewareChain) => +const createEoa = async () => fetch(`${BACKEND_URL}/wallet`, { method: 'POST', headers: { From ce36f22aece2d6e95b44ca8d5ef838ddef10a1a1 Mon Sep 17 00:00:00 2001 From: truemiller <mlxndrj@gmail.com> Date: Mon, 25 Nov 2024 01:36:15 +0000 Subject: [PATCH 385/463] refactor: large fix --- electron/main.js | 1 + frontend/abis/erc20.ts | 20 ++- frontend/components/AddressLink.tsx | 2 +- .../header/AgentButton/AgentButton.tsx | 50 +++--- .../AgentButton/AgentNotRunningButton.tsx | 2 +- .../MainPage/header/LastTransaction.tsx | 2 +- frontend/components/MainPage/header/index.tsx | 9 +- frontend/components/MainPage/index.tsx | 4 +- .../MainPage/sections/AddFundsSection.tsx | 6 +- .../AlertSections/AddBackupWalletAlert.tsx | 2 - .../NoAvailableSlotsOnTheContract.tsx | 23 ++- .../MainPage/sections/GasBalanceSection.tsx | 28 +-- .../StakingRewardsThisEpoch.tsx | 57 +++--- .../sections/RewardsSection/index.tsx | 4 +- .../sections/StakingContractUpdate.tsx | 25 ++- .../CantMigrateAlert.tsx | 2 +- .../StakingContractSection/MigrateButton.tsx | 4 +- .../StakingContractSection/index.tsx | 104 +++++------ .../StakingContractSection/useMigrate.tsx | 41 +++-- .../components/ManageStakingPage/index.tsx | 94 ++++++---- .../RewardsHistory/RewardsHistory.tsx | 2 +- .../SettingsPage/AddBackupWalletPage.tsx | 2 +- .../SettingsPage/DebugInfoSection.tsx | 4 +- .../SetupPage/Create/SetupEoaFunding.tsx | 4 +- .../components/SetupPage/SetupWelcome.tsx | 8 +- frontend/components/errors/ErrorComponent.tsx | 3 + frontend/config/chains.ts | 24 +-- frontend/config/stakingPrograms/index.ts | 2 +- frontend/config/tokens.ts | 16 +- frontend/constants/providers.ts | 17 +- frontend/constants/react-query-keys.ts | 2 +- frontend/constants/urls.ts | 4 +- frontend/context/BalanceProvider.tsx | 169 ++++++++++++------ frontend/context/MasterWalletProvider.tsx | 35 ++-- frontend/context/RewardProvider.tsx | 16 +- frontend/context/ServicesProvider.tsx | 8 +- .../StakingContractDetailsProvider.tsx | 30 ++-- frontend/context/StakingProgramProvider.tsx | 91 ++++++---- frontend/enums/Chain.ts | 4 +- frontend/hooks/useBalanceContext.ts | 41 ++++- frontend/hooks/useLogs.ts | 8 +- frontend/hooks/useMultisig.ts | 4 +- frontend/hooks/useNeedsFunds.ts | 36 ++-- frontend/hooks/useStakingContractDetails.ts | 57 ++---- frontend/hooks/useStakingProgram.ts | 57 +++--- frontend/service/Wallet.ts | 2 +- frontend/utils/truncate.ts | 5 +- .../js/tenderly-optimus-fund-master-safes.js | 66 +++++-- 48 files changed, 702 insertions(+), 495 deletions(-) create mode 100644 frontend/components/errors/ErrorComponent.tsx diff --git a/electron/main.js b/electron/main.js index ca61021ef..4157b081d 100644 --- a/electron/main.js +++ b/electron/main.js @@ -1,3 +1,4 @@ +require('dotenv').config(); const { app, BrowserWindow, diff --git a/frontend/abis/erc20.ts b/frontend/abis/erc20.ts index 2c32e58c0..7d91234f9 100644 --- a/frontend/abis/erc20.ts +++ b/frontend/abis/erc20.ts @@ -1,5 +1,23 @@ import { Abi } from '@/types/Abi'; export const ERC20_BALANCE_OF_STRING_FRAGMENT: Abi = [ - 'function balanceOf(address owner) view returns (uint256)', + { + constant: true, + inputs: [ + { + name: '_owner', + type: 'address', + }, + ], + name: 'balanceOf', + outputs: [ + { + name: 'balance', + type: 'uint256', + }, + ], + payable: false, + stateMutability: 'view', + type: 'function', + }, ]; diff --git a/frontend/components/AddressLink.tsx b/frontend/components/AddressLink.tsx index 21273573c..d26fa0235 100644 --- a/frontend/components/AddressLink.tsx +++ b/frontend/components/AddressLink.tsx @@ -15,7 +15,7 @@ export const AddressLink = ({ return ( <a target="_blank" - href={`${EXPLORER_URL_BY_MIDDLEWARE_CHAIN[MiddlewareChain.OPTIMISM]}/address/${address}`} + href={`${EXPLORER_URL_BY_MIDDLEWARE_CHAIN[MiddlewareChain.GNOSIS]}/address/${address}`} > {truncateAddress(address)} diff --git a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx index f3ef165f6..7b9705df7 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx @@ -1,12 +1,12 @@ import { Button } from 'antd'; +import { ErrorBoundary } from 'next/dist/client/components/error-boundary'; import { useMemo } from 'react'; import { MiddlewareDeploymentStatus } from '@/client'; +import { ErrorComponent } from '@/components/errors/ErrorComponent'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useActiveStakingContractInfo } from '@/hooks/useStakingContractDetails'; -import { useStakingProgram } from '@/hooks/useStakingProgram'; -import { assertRequired } from '@/types/Util'; import { CannotStartAgentDueToUnexpectedError, @@ -18,29 +18,25 @@ import { AgentStartingButton } from './AgentStartingButton'; import { AgentStoppingButton } from './AgentStoppingButton'; export const AgentButton = () => { - const { selectedService } = useServices(); - const { activeStakingProgramId } = useStakingProgram(); + const { selectedService, isFetched: isServicesLoaded } = useServices(); - const serviceConfigId = selectedService?.service_config_id; - - const { - service, - deploymentStatus: serviceStatus, - isLoaded, - } = useService(serviceConfigId); - - assertRequired( - // TODO: review whether this causes agent button to not render - activeStakingProgramId, - 'Active staking program ID is required', + const { service, deploymentStatus: serviceStatus } = useService( + selectedService?.service_config_id, ); - const { isEligibleForStaking, isAgentEvicted } = - useActiveStakingContractInfo(); + const { + isEligibleForStaking, + isAgentEvicted, + isActiveStakingContractDetailsLoaded, + } = useActiveStakingContractInfo(); - return useMemo(() => { - if (!isLoaded) { - return <Button type="primary" size="large" disabled loading />; + const button = useMemo(() => { + if (!isServicesLoaded || !isActiveStakingContractDetailsLoaded) { + return ( + <Button type="primary" size="large" disabled loading> + Loading... + </Button> + ); } if (serviceStatus === MiddlewareDeploymentStatus.STOPPING) { @@ -69,5 +65,15 @@ export const AgentButton = () => { } return <CannotStartAgentDueToUnexpectedError />; - }, [isLoaded, serviceStatus, isEligibleForStaking, isAgentEvicted, service]); + }, [ + isServicesLoaded, + serviceStatus, + isEligibleForStaking, + isAgentEvicted, + service, + ]); + + return ( + <ErrorBoundary errorComponent={ErrorComponent}>{button}</ErrorBoundary> + ); }; diff --git a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx index 9e5303012..726e0dec2 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentNotRunningButton.tsx @@ -56,7 +56,7 @@ export const AgentNotRunningButton = () => { const { isAllStakingContractDetailsRecordLoaded, setIsPaused: setIsStakingContractInfoPollingPaused, - refetchActiveStakingContractDetails, + refetchSelectedStakingContractDetails: refetchActiveStakingContractDetails, } = useStakingContractContext(); const { activeStakingProgramId } = useStakingProgram(); diff --git a/frontend/components/MainPage/header/LastTransaction.tsx b/frontend/components/MainPage/header/LastTransaction.tsx index 23373cd42..bafe15bb5 100644 --- a/frontend/components/MainPage/header/LastTransaction.tsx +++ b/frontend/components/MainPage/header/LastTransaction.tsx @@ -86,7 +86,7 @@ export const LastTransaction = ({ serviceConfigId }: LastTransactionProps) => { className="text-xs pointer hover-underline" onClick={() => window.open( - `${EXPLORER_URL_BY_MIDDLEWARE_CHAIN[MiddlewareChain.OPTIMISM]}/tx/${transaction.hash}`, + `${EXPLORER_URL_BY_MIDDLEWARE_CHAIN[MiddlewareChain.GNOSIS]}/tx/${transaction.hash}`, ) } > diff --git a/frontend/components/MainPage/header/index.tsx b/frontend/components/MainPage/header/index.tsx index c325b83f6..9ce1e696d 100644 --- a/frontend/components/MainPage/header/index.tsx +++ b/frontend/components/MainPage/header/index.tsx @@ -6,7 +6,6 @@ import { useBalanceContext } from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; -import { useStakingProgram } from '@/hooks/useStakingProgram'; import { FirstRunModal } from '../modals/FirstRunModal'; import { AgentButton } from './AgentButton/AgentButton'; @@ -37,19 +36,13 @@ export const MainHeader = () => { const [isFirstRunModalOpen, setIsFirstRunModalOpen] = useState(false); const handleModalClose = useCallback(() => setIsFirstRunModalOpen(false), []); - const { selectedService } = useServices(); - const { isLoaded: isServiceLoaded } = useService( - selectedService?.service_config_id, - ); - const { isActiveStakingProgramLoaded } = useStakingProgram(); - useSetupTrayIcon(); // TODO: support loading state return ( <Flex justify="start" align="center" gap={10}> <AgentHead /> - {isServiceLoaded && isActiveStakingProgramLoaded && <AgentButton />} + <AgentButton /> <FirstRunModal open={isFirstRunModalOpen} onClose={handleModalClose} /> </Flex> ); diff --git a/frontend/components/MainPage/index.tsx b/frontend/components/MainPage/index.tsx index c7c2997e1..a0917bc50 100644 --- a/frontend/components/MainPage/index.tsx +++ b/frontend/components/MainPage/index.tsx @@ -21,7 +21,7 @@ import { KeepAgentRunningSection } from './sections/KeepAgentRunningSection'; import { MainNeedsFunds } from './sections/NeedsFundsSection'; import { MainOlasBalance } from './sections/OlasBalanceSection'; import { RewardsSection } from './sections/RewardsSection'; -import { StakingContractUpdate } from './sections/StakingContractUpdate'; +import { StakingContractSection } from './sections/StakingContractUpdate'; export const Main = () => { const { goto } = usePageState(); @@ -96,7 +96,7 @@ export const Main = () => { <MainOlasBalance isBorderTopVisible={!hideMainOlasBalanceTopBorder} /> <RewardsSection /> <KeepAgentRunningSection /> - <StakingContractUpdate /> + <StakingContractSection /> <GasBalanceSection /> <MainNeedsFunds /> <AddFundsSection /> diff --git a/frontend/components/MainPage/sections/AddFundsSection.tsx b/frontend/components/MainPage/sections/AddFundsSection.tsx index ba7dfb8df..8a08640c0 100644 --- a/frontend/components/MainPage/sections/AddFundsSection.tsx +++ b/frontend/components/MainPage/sections/AddFundsSection.tsx @@ -106,7 +106,7 @@ export const OpenAddFundsSection = forwardRef<HTMLDivElement>((_, ref) => { fundingAddress={masterSafeAddress} handleCopy={handleCopyAddress} /> - <AddFundsGetTokensSection /> + {/* <AddFundsGetTokensSection /> */} </Flex> ); }); @@ -172,6 +172,8 @@ const AddFundsAddressSection = ({ </CardSection> ); +// TODO: readd when important to +// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars const AddFundsGetTokensSection = () => { const { selectedAgentConfig } = useServices(); const { evmHomeChainId: homeChainId } = selectedAgentConfig; @@ -185,7 +187,7 @@ const AddFundsGetTokensSection = () => { COW_SWAP_GNOSIS_XDAI_OLAS_URL } > - Get OLAS + {CHAIN_CONFIG[homeChainId].currency} on{' '} + Get OLAS + {CHAIN_CONFIG[homeChainId].nativeToken.symbol} on{' '} {CHAIN_CONFIG[homeChainId].name} {UNICODE_SYMBOLS.EXTERNAL_LINK} </Link> </CardSection> diff --git a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx index ed8def1fe..4acafea09 100644 --- a/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx +++ b/frontend/components/MainPage/sections/AlertSections/AddBackupWalletAlert.tsx @@ -15,11 +15,9 @@ export const AddBackupWalletAlert = () => { const { masterSafes } = useMasterWalletContext(); const { masterSafesOwners: owners, - masterSafesOwnersIsPending: ownersIsPending, masterSafesOwnersIsFetched: ownersIsFetched, } = useMultisigs(masterSafes); - if (ownersIsPending) return null; if (!ownersIsFetched) return null; // all safes have min 1 owner, more than 1 owner, there is a backup diff --git a/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx b/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx index 2037c16db..02d175449 100644 --- a/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx +++ b/frontend/components/MainPage/sections/AlertSections/NoAvailableSlotsOnTheContract.tsx @@ -5,7 +5,6 @@ import { Pages } from '@/enums/Pages'; import { usePageState } from '@/hooks/usePageState'; import { useActiveStakingContractInfo, - useStakingContractContext, useStakingContractDetails, } from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; @@ -17,17 +16,22 @@ const { Text } = Typography; export const NoAvailableSlotsOnTheContract = () => { const { goto } = usePageState(); - const { activeStakingProgramId, activeStakingProgramMeta } = - useStakingProgram(); + const { + isActiveStakingProgramLoaded, + selectedStakingProgramId, + selectedStakingProgramMeta, + } = useStakingProgram(); + + const { isServiceStaked, isActiveStakingContractDetailsLoaded } = + useActiveStakingContractInfo(); - const { isAllStakingContractDetailsRecordLoaded } = - useStakingContractContext(); - const { isServiceStaked } = useActiveStakingContractInfo(); const { hasEnoughServiceSlots } = useStakingContractDetails( - activeStakingProgramId, + selectedStakingProgramId, ); - if (!isAllStakingContractDetailsRecordLoaded) return null; + if (!isActiveStakingProgramLoaded) return null; + if (!isActiveStakingContractDetailsLoaded) return null; + if (hasEnoughServiceSlots) return null; if (isServiceStaked) return null; @@ -39,7 +43,8 @@ export const NoAvailableSlotsOnTheContract = () => { message={ <Flex justify="space-between" gap={4} vertical> <Text className="font-weight-600"> - No available staking slots on {activeStakingProgramMeta?.name || NA} + No available staking slots on{' '} + {selectedStakingProgramMeta?.name || NA} </Text> <span className="text-sm"> Select a contract with available slots to start your agent. diff --git a/frontend/components/MainPage/sections/GasBalanceSection.tsx b/frontend/components/MainPage/sections/GasBalanceSection.tsx index 55fef650e..a523c6b92 100644 --- a/frontend/components/MainPage/sections/GasBalanceSection.tsx +++ b/frontend/components/MainPage/sections/GasBalanceSection.tsx @@ -6,7 +6,10 @@ import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; import { EXPLORER_URL_BY_MIDDLEWARE_CHAIN } from '@/constants/urls'; -import { useBalanceContext } from '@/hooks/useBalanceContext'; +import { + useBalanceContext, + useMasterBalances, +} from '@/hooks/useBalanceContext'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; import { useStore } from '@/hooks/useStore'; @@ -36,48 +39,53 @@ const FineDot = styled(Dot)` `; const BalanceStatus = () => { - const { isLoaded, isLowBalance } = useBalanceContext(); + const { isLoaded: isBalanceLoaded } = useBalanceContext(); + const { isFetched: isServicesLoaded } = useServices(); + const { storeState } = useStore(); const { showNotification } = useElectronApi(); + const { isMasterSafeLowOnNativeGas } = useMasterBalances(); + const [isLowBalanceNotificationShown, setIsLowBalanceNotificationShown] = useState(false); // show notification if balance is too low useEffect(() => { - if (!isLoaded) return; + if (!isBalanceLoaded || !isServicesLoaded) return; if (!showNotification) return; if (!storeState?.isInitialFunded) return; - if (isLowBalance && !isLowBalanceNotificationShown) { + if (isMasterSafeLowOnNativeGas && !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 (!isLowBalance && isLowBalanceNotificationShown) { + if (!isMasterSafeLowOnNativeGas && isLowBalanceNotificationShown) { setIsLowBalanceNotificationShown(false); } }, [ - isLoaded, + isBalanceLoaded, + isServicesLoaded, isLowBalanceNotificationShown, - isLowBalance, + isMasterSafeLowOnNativeGas, showNotification, storeState?.isInitialFunded, ]); const status = useMemo(() => { - if (isNil(isLowBalance)) { + if (!isBalanceLoaded || !isServicesLoaded) { return { statusName: 'Loading...', StatusComponent: EmptyDot }; } - if (isLowBalance) { + if (isMasterSafeLowOnNativeGas) { return { statusName: 'Too low', StatusComponent: EmptyDot }; } return { statusName: 'Fine', StatusComponent: FineDot }; - }, [isLowBalance]); + }, [isBalanceLoaded, isMasterSafeLowOnNativeGas, isServicesLoaded]); const { statusName, StatusComponent } = status; return ( diff --git a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx index e8e9303f6..b504f1365 100644 --- a/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/StakingRewardsThisEpoch.tsx @@ -1,6 +1,7 @@ import { InfoCircleOutlined } from '@ant-design/icons'; import { useQuery } from '@tanstack/react-query'; -import { Popover, Typography } from 'antd'; +import { Popover, Skeleton, Typography } from 'antd'; +import { useMemo } from 'react'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { NA } from '@/constants/symbols'; @@ -39,36 +40,46 @@ const useEpochEndTime = () => { export const StakingRewardsThisEpoch = () => { const { data: epochEndTimeInMs } = useEpochEndTime(); + const { - activeStakingProgramMeta, - activeStakingProgramId, isActiveStakingProgramLoaded, + activeStakingProgramMeta, + defaultStakingProgramMeta, } = useStakingProgram(); - const stakingProgramMeta = activeStakingProgramMeta; + const stakingProgramMeta = isActiveStakingProgramLoaded + ? activeStakingProgramMeta || defaultStakingProgramMeta + : null; + + const popoverContent = useMemo(() => { + if (!isActiveStakingProgramLoaded) return <Skeleton.Input />; + if (!activeStakingProgramMeta) + return ( + <div style={{ maxWidth: POPOVER_WIDTH_MEDIUM }}> + You're not yet in a staking program! + </div> + ); + return ( + <div style={{ maxWidth: POPOVER_WIDTH_MEDIUM }}> + The epoch for {stakingProgramMeta?.name} ends each day at ~{' '} + <Text className="text-sm" strong> + {epochEndTimeInMs + ? `${formatToTime(epochEndTimeInMs * 1000)} (UTC)` + : NA} + </Text> + </div> + ); + }, [ + activeStakingProgramMeta, + epochEndTimeInMs, + isActiveStakingProgramLoaded, + stakingProgramMeta?.name, + ]); return ( <Text type="secondary"> Staking rewards this epoch  - <Popover - arrow={false} - content={ - isActiveStakingProgramLoaded && activeStakingProgramId ? ( - <div style={{ maxWidth: POPOVER_WIDTH_MEDIUM }}> - The epoch for {stakingProgramMeta?.name} ends each day at ~{' '} - <Text className="text-sm" strong> - {epochEndTimeInMs - ? `${formatToTime(epochEndTimeInMs * 1000)} (UTC)` - : NA} - </Text> - </div> - ) : ( - <div style={{ maxWidth: POPOVER_WIDTH_MEDIUM }}> - You're not yet in a staking program! - </div> - ) - } - > + <Popover arrow={false} content={popoverContent}> <InfoCircleOutlined /> </Popover> </Text> diff --git a/frontend/components/MainPage/sections/RewardsSection/index.tsx b/frontend/components/MainPage/sections/RewardsSection/index.tsx index 91c59671c..05aa2f47b 100644 --- a/frontend/components/MainPage/sections/RewardsSection/index.tsx +++ b/frontend/components/MainPage/sections/RewardsSection/index.tsx @@ -24,7 +24,7 @@ const getFormattedReward = (reward: number | undefined) => const DisplayRewards = () => { const { availableRewardsForEpochEth, isEligibleForRewards } = useReward(); - const { isLoaded } = useBalanceContext(); + const { isLoaded: isBalancesLoaded } = useBalanceContext(); const reward = getFormattedReward(availableRewardsForEpochEth); return ( @@ -36,7 +36,7 @@ const DisplayRewards = () => { borderbottom="true" > <StakingRewardsThisEpoch /> - {isLoaded ? ( + {isBalancesLoaded ? ( <Flex align="center" gap={12}> <Text className="text-xl font-weight-600">{reward} OLAS </Text> {isEligibleForRewards ? ( diff --git a/frontend/components/MainPage/sections/StakingContractUpdate.tsx b/frontend/components/MainPage/sections/StakingContractUpdate.tsx index d49c6fea1..860505d72 100644 --- a/frontend/components/MainPage/sections/StakingContractUpdate.tsx +++ b/frontend/components/MainPage/sections/StakingContractUpdate.tsx @@ -2,10 +2,10 @@ import { RightOutlined } from '@ant-design/icons'; import { Button, Flex, Skeleton, Typography } from 'antd'; import { useMemo } from 'react'; -import { MiddlewareDeploymentStatus } from '@/client'; import { NA } from '@/constants/symbols'; import { Pages } from '@/enums/Pages'; import { usePageState } from '@/hooks/usePageState'; +import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; import { useStakingContractContext } from '@/hooks/useStakingContractDetails'; import { useStakingProgram } from '@/hooks/useStakingProgram'; @@ -14,44 +14,41 @@ import { CardSection } from '../../styled/CardSection'; const { Text } = Typography; -export const StakingContractUpdate = () => { +export const StakingContractSection = () => { const { goto } = usePageState(); - const { isActiveStakingProgramLoaded, activeStakingProgramMeta } = + const { isActiveStakingProgramLoaded, selectedStakingProgramMeta } = useStakingProgram(); const { isAllStakingContractDetailsRecordLoaded } = useStakingContractContext(); const { selectedService } = useServices(); - const serviceStatus = selectedService?.deploymentStatus; - const serviceIsTransitioning = useMemo( - () => - serviceStatus === MiddlewareDeploymentStatus.DEPLOYING || - serviceStatus === MiddlewareDeploymentStatus.STOPPING, - [serviceStatus], + const { isServiceTransitioning } = useService( + selectedService?.service_config_id, ); const gotoManageStakingButton = useMemo(() => { if (!isActiveStakingProgramLoaded) return <Skeleton.Input />; + return ( <Button type="link" className="p-0" onClick={() => goto(Pages.ManageStaking)} disabled={ - !isAllStakingContractDetailsRecordLoaded || serviceIsTransitioning + !isAllStakingContractDetailsRecordLoaded || isServiceTransitioning } > - {activeStakingProgramMeta?.name || NA} + {selectedStakingProgramMeta?.name || NA} <RightOutlined /> </Button> ); }, [ - goto, isActiveStakingProgramLoaded, isAllStakingContractDetailsRecordLoaded, - serviceIsTransitioning, - activeStakingProgramMeta?.name, + isServiceTransitioning, + selectedStakingProgramMeta?.name, + goto, ]); return ( diff --git a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx index 62977ed07..538bfb73a 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/CantMigrateAlert.tsx @@ -45,7 +45,7 @@ const AlertInsufficientMigrationFunds = ({ if (!isBalanceLoaded) return; if (isNil(masterSafeBalances) || isEmpty(masterSafeBalances)) return; masterSafeBalances.reduce( - (acc, { chainId, symbol, balance }) => { + (acc, { evmChainId: chainId, symbol, balance }) => { if (chainId === selectedAgentConfig.evmHomeChainId) { acc[symbol] = balance; } diff --git a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx index 82948d398..1c2f6d165 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/MigrateButton.tsx @@ -47,11 +47,11 @@ export const MigrateButton = ({ const { setIsPaused: setIsBalancePollingPaused } = useBalanceContext(); - const { initialDefaultStakingProgramId } = useStakingProgram(); + const { defaultStakingProgramId } = useStakingProgram(); const { activeStakingContractDetails, isActiveStakingContractDetailsLoaded } = useActiveStakingContractInfo(); const { stakingContractInfo: defaultStakingContractInfo } = - useStakingContractDetails(initialDefaultStakingProgramId); + useStakingContractDetails(defaultStakingProgramId); const currentStakingContractInfo = useMemo(() => { if (!isActiveStakingContractDetailsLoaded) return; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx index 9a17bbd83..6fc85a6c1 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/index.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/index.tsx @@ -8,7 +8,6 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { StakingProgramStatus } from '@/enums/StakingProgramStatus'; import { useServices } from '@/hooks/useServices'; import { useStakingProgram } from '@/hooks/useStakingProgram'; -import { asEvmChainId } from '@/utils/middlewareHelpers'; import { CantMigrateAlert } from './CantMigrateAlert'; import { MigrateButton } from './MigrateButton'; @@ -37,12 +36,13 @@ export const StakingContractSection = ({ const { token } = useToken(); const { migrateValidation } = useMigrate(stakingProgramId); const { - initialDefaultStakingProgramId, + defaultStakingProgramId, activeStakingProgramId, - activeStakingProgramMeta, + allStakingProgramsMeta, activeStakingProgramAddress, + isActiveStakingProgramLoaded, } = useStakingProgram(); - const { selectedService } = useServices(); + const { selectedAgentConfig } = useServices(); // /** // * Returns `true` if this stakingProgram is active, @@ -55,6 +55,8 @@ export const StakingContractSection = ({ // }, [activeStakingProgramId, defaultStakingProgramId, stakingProgramId]); const contractTagStatus = useMemo(() => { + if (!isActiveStakingProgramLoaded) return null; + if (activeStakingProgramId === stakingProgramId) { return StakingProgramStatus.Active; } @@ -62,7 +64,7 @@ export const StakingContractSection = ({ // Pearl is not staked, set as Selected if default if ( !activeStakingProgramId && - stakingProgramId === initialDefaultStakingProgramId + stakingProgramId === defaultStakingProgramId ) { return StakingProgramStatus.Default; } @@ -71,64 +73,66 @@ export const StakingContractSection = ({ return null; }, [ activeStakingProgramId, - initialDefaultStakingProgramId, + defaultStakingProgramId, + isActiveStakingProgramLoaded, stakingProgramId, ]); - const showMigrateButton = stakingProgramId !== activeStakingProgramId; + const showMigrateButton = + !isActiveStakingProgramLoaded && + stakingProgramId !== activeStakingProgramId; const showFundingButton = useMemo(() => { + if (!isActiveStakingProgramLoaded) return false; if (migrateValidation.canMigrate) return false; return ( migrateValidation.reason === CantMigrateReason.InsufficientOlasToMigrate || migrateValidation.reason === CantMigrateReason.InsufficientGasToMigrate ); - }, [migrateValidation]); + }, [isActiveStakingProgramLoaded, migrateValidation]); - const evmChainId = asEvmChainId(selectedService?.home_chain); + const evmChainId = selectedAgentConfig.evmHomeChainId; return ( - <> - <CardSection - style={{ - padding: '16px 24px', - backgroundColor: contractTagStatus ? token.colorPrimaryBg : undefined, - }} - borderbottom="true" - vertical - gap={16} - > - <Flex gap={12}> - <Title level={5} className="m-0"> - {`${activeStakingProgramMeta?.name} contract`} - - - - - - - {evmChainId && ( - - View contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} - - )} - - {!migrateValidation.canMigrate && ( - - )} - - {showMigrateButton && ( - - )} - {showFundingButton && } - - + + + + {allStakingProgramsMeta[stakingProgramId]?.name || 'Unknown'} + + + + + + + {evmChainId && ( + + View contract details {UNICODE_SYMBOLS.EXTERNAL_LINK} + + )} + + {!migrateValidation.canMigrate && ( + + )} + + {showMigrateButton && ( + + )} + {showFundingButton && } + ); }; diff --git a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx index d3aecf1f5..9b629e216 100644 --- a/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx +++ b/frontend/components/ManageStakingPage/StakingContractSection/useMigrate.tsx @@ -43,7 +43,7 @@ type MigrateValidation = reason: CantMigrateReason; }; -export const useMigrate = (stakingProgramId: StakingProgramId) => { +export const useMigrate = (migrateToStakingProgramId: StakingProgramId) => { const { isFetched: isServicesLoaded, selectedAgentConfig, @@ -71,24 +71,29 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { const { isServiceStaked, isServiceStakedForMinimumDuration } = useActiveStakingContractInfo(); const { stakingContractInfo, hasEnoughServiceSlots } = - useStakingContractDetails(stakingProgramId); + useStakingContractDetails(migrateToStakingProgramId); const safeOlasBalance = useMemo(() => { if (!isBalanceLoaded) return 0; if (isNil(masterSafeBalances) || isEmpty(masterSafeBalances)) return 0; - masterSafeBalances.reduce((acc, { chainId, symbol, balance }) => { - if (chainId === homeChainId && symbol === TokenSymbol.OLAS) - return acc + balance; - return acc; - }, 0); + masterSafeBalances.reduce( + (acc, { evmChainId: chainId, symbol, balance }) => { + if (chainId === homeChainId && symbol === TokenSymbol.OLAS) + return acc + balance; + return acc; + }, + 0, + ); }, [homeChainId, isBalanceLoaded, masterSafeBalances]); const minimumOlasRequiredToMigrate = useMemo( () => - STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][stakingProgramId] - .stakingRequirements[TokenSymbol.OLAS], - [selectedAgentConfig.evmHomeChainId, stakingProgramId], + STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][ + migrateToStakingProgramId + ]?.stakingRequirements[TokenSymbol.OLAS], + [selectedAgentConfig.evmHomeChainId, migrateToStakingProgramId], ); + const hasEnoughOlasToMigrate = useMemo(() => { if (!isBalanceLoaded) return false; if (isNil(safeOlasBalance)) return false; @@ -150,7 +155,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { } // general requirements - if (activeStakingProgramId === stakingProgramId) { + if (activeStakingProgramId === migrateToStakingProgramId) { return { canMigrate: false, reason: CantMigrateReason.ContractAlreadySelected, @@ -198,10 +203,10 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { // user must be staked from hereon if ( - !STAKING_PROGRAMS[homeChainId][stakingProgramId].deprecated || - !STAKING_PROGRAMS[homeChainId][stakingProgramId].agentsSupported.includes( - selectedAgentType, - ) + !STAKING_PROGRAMS[homeChainId][migrateToStakingProgramId].deprecated || + !STAKING_PROGRAMS[homeChainId][ + migrateToStakingProgramId + ].agentsSupported.includes(selectedAgentType) ) { return { canMigrate: false, @@ -223,7 +228,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { isAllStakingContractDetailsRecordLoaded, stakingContractInfo, activeStakingProgramId, - stakingProgramId, + migrateToStakingProgramId, hasEnoughOlasToMigrate, isServiceStaked, homeChainId, @@ -269,7 +274,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { } const stakingContractInfo = - allStakingContractDetailsRecord?.[stakingProgramId]; + allStakingContractDetailsRecord?.[migrateToStakingProgramId]; if (!stakingContractInfo) { return { @@ -323,7 +328,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => { hasEnoughEthForInitialFunding, isAllStakingContractDetailsRecordLoaded, allStakingContractDetailsRecord, - stakingProgramId, + migrateToStakingProgramId, hasEnoughOlasForFirstRun, serviceStatus, ]); diff --git a/frontend/components/ManageStakingPage/index.tsx b/frontend/components/ManageStakingPage/index.tsx index dd009f48e..b20da37fc 100644 --- a/frontend/components/ManageStakingPage/index.tsx +++ b/frontend/components/ManageStakingPage/index.tsx @@ -1,5 +1,6 @@ import { CloseOutlined } from '@ant-design/icons'; import { Button, Card } from 'antd'; +import { useMemo } from 'react'; import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { Pages } from '@/enums/Pages'; @@ -16,37 +17,62 @@ import { WhatAreStakingContractsSection } from './WhatAreStakingContracts'; export const ManageStakingPage = () => { const { goto } = usePageState(); const { selectedAgentConfig } = useServices(); - const { activeStakingProgramId } = useStakingProgram(); - - const orderedStakingProgramIds: StakingProgramId[] = Object.values( - StakingProgramId, - ).reduce((acc: StakingProgramId[], stakingProgramId: StakingProgramId) => { - // put the active staking program at the top - if (stakingProgramId === activeStakingProgramId) { - return [stakingProgramId, ...acc]; - } - - // put default at the top if no activeStakingProgram - if (activeStakingProgramId) return [stakingProgramId, ...acc]; - - // if the program is deprecated, ignore it - if ( - STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][stakingProgramId] - .deprecated - ) { - return acc; - } - - // otherwise, append to the end - return [...acc, stakingProgramId]; - }, []); + const { + activeStakingProgramId, + isActiveStakingProgramLoaded, + defaultStakingProgramId, + } = useStakingProgram(); + + const currentStakingProgramId = isActiveStakingProgramLoaded + ? activeStakingProgramId || defaultStakingProgramId + : null; + + const stakingProgramIdsAvailable = Object.keys( + STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId], + ).map((stakingProgramIdKey) => stakingProgramIdKey as StakingProgramId); + + const orderedStakingProgramIds = useMemo( + () => + stakingProgramIdsAvailable.reduce( + (acc: StakingProgramId[], stakingProgramId: StakingProgramId) => { + if (!isActiveStakingProgramLoaded) return acc; + + // put the active staking program at the top + if (stakingProgramId === currentStakingProgramId) { + return [stakingProgramId, ...acc]; + } + + // if the program is deprecated, ignore it + if ( + STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][ + stakingProgramId + ].deprecated + ) { + return acc; + } + + // otherwise, append to the end + return [...acc, stakingProgramId]; + }, + [], + ), + [ + isActiveStakingProgramLoaded, + selectedAgentConfig.evmHomeChainId, + currentStakingProgramId, + stakingProgramIdsAvailable, + ], + ); const otherStakingProgramIds = orderedStakingProgramIds.filter( (stakingProgramId) => { + if (!isActiveStakingProgramLoaded) return false; + const info = STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][stakingProgramId]; + if (!info) return false; - if (activeStakingProgramId === stakingProgramId) return false; + if (currentStakingProgramId === stakingProgramId) return false; if (info.deprecated) return false; return true; }, @@ -72,11 +98,12 @@ export const ManageStakingPage = () => { > - {activeStakingProgramId && ( - - )} + {isActiveStakingProgramLoaded && + (activeStakingProgramId || defaultStakingProgramId) && ( + + )} { {`Browse ${otherStakingProgramIds.length} staking contract${otherStakingProgramIds.length > 1 ? 's' : ''}.`} - {otherStakingProgramIds.map((stakingProgramId) => ( - + {otherStakingProgramIds.map((otherId) => ( + ))} ); diff --git a/frontend/components/RewardsHistory/RewardsHistory.tsx b/frontend/components/RewardsHistory/RewardsHistory.tsx index 0783050fd..e27c2dd37 100644 --- a/frontend/components/RewardsHistory/RewardsHistory.tsx +++ b/frontend/components/RewardsHistory/RewardsHistory.tsx @@ -130,7 +130,7 @@ const EpochTime = ({ epoch }: { epoch: EpochDetails }) => { {timePeriod} End of epoch transaction {UNICODE_SYMBOLS.EXTERNAL_LINK} diff --git a/frontend/components/SettingsPage/AddBackupWalletPage.tsx b/frontend/components/SettingsPage/AddBackupWalletPage.tsx index ac6d33638..a591aedd4 100644 --- a/frontend/components/SettingsPage/AddBackupWalletPage.tsx +++ b/frontend/components/SettingsPage/AddBackupWalletPage.tsx @@ -24,7 +24,7 @@ export const AddBackupWalletPage = () => { if (isNil(masterEoaBalances) || isEmpty(masterEoaBalances)) return false; const masterEoaNativeBalance = masterEoaBalances.find( - ({ isNative, chainId }) => isNative && chainId === homeChainId, + ({ isNative, evmChainId: chainId }) => isNative && chainId === homeChainId, )?.balance; if (isNil(masterEoaNativeBalance)) return false; diff --git a/frontend/components/SettingsPage/DebugInfoSection.tsx b/frontend/components/SettingsPage/DebugInfoSection.tsx index 8f3192b6c..e6e81a07c 100644 --- a/frontend/components/SettingsPage/DebugInfoSection.tsx +++ b/frontend/components/SettingsPage/DebugInfoSection.tsx @@ -47,7 +47,7 @@ const getBalanceData = (walletBalances: WalletBalanceResult[]) => { const result: { [chainId: number]: { [tokenSymbol: string]: number } } = {}; for (const walletBalanceResult of walletBalances) { - const { chainId, symbol } = walletBalanceResult; + const { evmChainId: chainId, symbol } = walletBalanceResult; if (!result[chainId]) result[chainId] = {}; if (!result[chainId][symbol]) result[chainId][symbol] = 0; result[chainId][symbol] += walletBalanceResult.balance; @@ -213,7 +213,7 @@ export const DebugInfoSection = () => { walletBalances.filter( (walletBalance) => walletBalance.walletAddress === serviceWallet.address && - walletBalance.chainId === serviceWallet.evmChainId, + walletBalance.evmChainId === serviceWallet.evmChainId, ), ), address: serviceWallet.address, diff --git a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx index 48b3cc3f1..6eaec1487 100644 --- a/frontend/components/SetupPage/Create/SetupEoaFunding.tsx +++ b/frontend/components/SetupPage/Create/SetupEoaFunding.tsx @@ -238,7 +238,7 @@ export const SetupEoaFunding = () => { (balance) => balance.walletAddress === masterEoaAddress, ); const isFunded = - eoaBalance?.chainId === EvmChainId.Gnosis && + eoaBalance?.evmChainId === EvmChainId.Gnosis && eoaBalance.balance >= MIN_ETH_BALANCE_THRESHOLDS[EvmChainId.Gnosis].safeCreation; @@ -246,7 +246,7 @@ export const SetupEoaFunding = () => { - {`Deposit ${currentFundingMapObject.requiredEth} ${currentFundingMapObject.chainConfig.currency} on ${currentFundingMapObject.chainConfig.name}`} + {`Deposit ${currentFundingMapObject.requiredEth} ${currentFundingMapObject.chainConfig.nativeToken} on ${currentFundingMapObject.chainConfig.name}`} The app needs these funds to create your account on-chain. diff --git a/frontend/components/SetupPage/SetupWelcome.tsx b/frontend/components/SetupPage/SetupWelcome.tsx index fc648f069..c39009b63 100644 --- a/frontend/components/SetupPage/SetupWelcome.tsx +++ b/frontend/components/SetupPage/SetupWelcome.tsx @@ -140,7 +140,7 @@ export const SetupWelcomeLogin = () => { masterWallets: wallets, masterEoa, } = useMasterWalletContext(); - const { isLoaded: isBalanceLoaded } = useBalanceContext(); + const { isLoaded: isBalanceLoaded, updateBalances } = useBalanceContext(); const { masterWalletBalances } = useMasterBalances(); const masterSafe = @@ -149,6 +149,7 @@ export const SetupWelcomeLogin = () => { selectedService?.home_chain && safe.evmChainId === asEvmChainId(selectedService?.home_chain), ) ?? null; + const eoaBalanceEth = masterWalletBalances?.find( (balance) => balance.walletAddress === masterEoa?.address, ); @@ -162,7 +163,8 @@ export const SetupWelcomeLogin = () => { async ({ password }: { password: string }) => { setIsLoggingIn(true); AccountService.loginAccount(password) - .then(() => { + .then(async () => { + await updateBalances(); setCanNavigate(true); }) .catch((e) => { @@ -171,7 +173,7 @@ export const SetupWelcomeLogin = () => { message.error('Invalid password'); }); }, - [], + [updateBalances], ); useEffect(() => { diff --git a/frontend/components/errors/ErrorComponent.tsx b/frontend/components/errors/ErrorComponent.tsx new file mode 100644 index 000000000..12765eb20 --- /dev/null +++ b/frontend/components/errors/ErrorComponent.tsx @@ -0,0 +1,3 @@ +export const ErrorComponent = () => { + return Error; +}; diff --git a/frontend/config/chains.ts b/frontend/config/chains.ts index 95a0dc3e7..c601a55db 100644 --- a/frontend/config/chains.ts +++ b/frontend/config/chains.ts @@ -6,50 +6,52 @@ import { MiddlewareChain as MiddlewareChainId } from '@/client'; import { EvmChainId } from '@/enums/Chain'; import { TokenSymbol } from '@/enums/Token'; +import { TOKEN_CONFIG, TokenConfig } from './tokens'; + type HttpUrl = `http${'s' | ''}://${string}`; type ChainConfig = { name: string; - currency: string; - chainId: number; + nativeToken: TokenConfig; + evmChainId: number; middlewareChain: MiddlewareChainId; rpc: HttpUrl; }; export const GNOSIS_CHAIN_CONFIG: ChainConfig = { - chainId: EvmChainId.Gnosis, + evmChainId: EvmChainId.Gnosis, name: 'Gnosis', - currency: TokenSymbol.XDAI, + nativeToken: TOKEN_CONFIG[EvmChainId.Gnosis][TokenSymbol.XDAI], middlewareChain: MiddlewareChainId.GNOSIS, rpc: process.env.GNOSIS_RPC as HttpUrl, }; export const OPTIMISM_CHAIN_CONFIG: ChainConfig = { - chainId: EvmChainId.Optimism, + evmChainId: EvmChainId.Optimism, name: 'Optimism', - currency: TokenSymbol.ETH, + nativeToken: TOKEN_CONFIG[EvmChainId.Optimism][TokenSymbol.ETH], middlewareChain: MiddlewareChainId.OPTIMISM, rpc: process.env.OPTIMISM_RPC as HttpUrl, }; export const BASE_CHAIN_CONFIG: ChainConfig = { - chainId: EvmChainId.Base, + evmChainId: EvmChainId.Base, name: 'Base', - currency: TokenSymbol.ETH, + nativeToken: TOKEN_CONFIG[EvmChainId.Base][TokenSymbol.ETH], middlewareChain: MiddlewareChainId.BASE, rpc: process.env.BASE_RPC as HttpUrl, }; export const ETHEREUM_CHAIN_CONFIG: ChainConfig = { - chainId: EvmChainId.Ethereum, + evmChainId: EvmChainId.Ethereum, name: 'Ethereum', - currency: TokenSymbol.ETH, + nativeToken: TOKEN_CONFIG[EvmChainId.Ethereum][TokenSymbol.ETH], middlewareChain: MiddlewareChainId.ETHEREUM, rpc: process.env.GNOSIS_RPC as HttpUrl, }; export const CHAIN_CONFIG: { - [chainId: number]: ChainConfig; + [evmChainId: number]: ChainConfig; } = { [EvmChainId.Base]: BASE_CHAIN_CONFIG, [EvmChainId.Ethereum]: ETHEREUM_CHAIN_CONFIG, diff --git a/frontend/config/stakingPrograms/index.ts b/frontend/config/stakingPrograms/index.ts index 5a76eca78..c19b6f682 100644 --- a/frontend/config/stakingPrograms/index.ts +++ b/frontend/config/stakingPrograms/index.ts @@ -50,7 +50,7 @@ export const STAKING_PROGRAM_ADDRESS: { // [ChainId.Optimism]: OPTIMISM_STAKING_PROGRAMS_CONTRACT_ADDRESSES, }; -export const INITIAL_DEFAULT_STAKING_PROGRAM_IDS: { +export const DEFAULT_STAKING_PROGRAM_IDS: { [chainId: number | EvmChainId]: StakingProgramId; } = { [EvmChainId.Gnosis]: StakingProgramId.PearlBeta, diff --git a/frontend/config/tokens.ts b/frontend/config/tokens.ts index 6ccb38475..7cabcf7d8 100644 --- a/frontend/config/tokens.ts +++ b/frontend/config/tokens.ts @@ -15,12 +15,14 @@ export type Erc20TokenConfig = { address: Address; tokenType: TokenType.Erc20; decimals: number; + symbol: TokenSymbol; }; export type NativeTokenConfig = { - address?: Address; + address?: undefined; tokenType: TokenType.NativeGas; decimals: number; + symbol: TokenSymbol; }; export type TokenConfig = Erc20TokenConfig | NativeTokenConfig; @@ -31,14 +33,15 @@ export type ChainTokenConfig = { export const GNOSIS_TOKEN_CONFIG: ChainTokenConfig = { [TokenSymbol.XDAI]: { - address: '0x0001A500A6B18995B03f44bb040A5fFc28E45CB0', decimals: 18, tokenType: TokenType.NativeGas, + symbol: TokenSymbol.XDAI, }, [TokenSymbol.OLAS]: { address: '0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f', decimals: 18, tokenType: TokenType.Erc20, + symbol: TokenSymbol.OLAS, }, }; @@ -46,23 +49,27 @@ export const OPTIMISM_TOKEN_CONFIG: ChainTokenConfig = { [TokenSymbol.ETH]: { tokenType: TokenType.NativeGas, decimals: 18, + symbol: TokenSymbol.ETH, }, [TokenSymbol.OLAS]: { address: '0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527', decimals: 18, tokenType: TokenType.Erc20, + symbol: TokenSymbol.OLAS, }, -} satisfies ChainTokenConfig; +}; export const ETHEREUM_TOKEN_CONFIG: ChainTokenConfig = { [TokenSymbol.ETH]: { tokenType: TokenType.NativeGas, decimals: 18, + symbol: TokenSymbol.ETH, }, [TokenSymbol.OLAS]: { address: '0x0001A500A6B18995B03f44bb040A5fFc28E45CB0', decimals: 18, tokenType: TokenType.Erc20, + symbol: TokenSymbol.OLAS, }, /** * @warning USDC is a special case, it has 6 decimals, not 18. @@ -73,6 +80,7 @@ export const ETHEREUM_TOKEN_CONFIG: ChainTokenConfig = { address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', decimals: 6, tokenType: TokenType.Erc20, + symbol: TokenSymbol.USDC, }, }; @@ -80,11 +88,13 @@ export const BASE_TOKEN_CONFIG: ChainTokenConfig = { [TokenSymbol.ETH]: { tokenType: TokenType.NativeGas, decimals: 18, + symbol: TokenSymbol.ETH, }, [TokenSymbol.OLAS]: { address: '0x4B1a99467a284CC690e3237bc69105956816F762', decimals: 18, tokenType: TokenType.Erc20, + symbol: TokenSymbol.OLAS, }, }; diff --git a/frontend/constants/providers.ts b/frontend/constants/providers.ts index 0cf4991d3..028adc630 100644 --- a/frontend/constants/providers.ts +++ b/frontend/constants/providers.ts @@ -1,26 +1,29 @@ import { ethers } from 'ethers'; import { Provider as MulticallProvider } from 'ethers-multicall'; +import { EvmChainId } from '@/enums/Chain'; + import { CHAIN_CONFIG } from '../config/chains'; type Providers = { - [chainIdKey in keyof typeof CHAIN_CONFIG]: { + [evmChainId in EvmChainId]: { provider: ethers.providers.JsonRpcProvider; multicallProvider: MulticallProvider; }; }; -export const PROVIDERS = Object.entries(CHAIN_CONFIG).reduce( - (acc, [chainConfigKey, { rpc, name, chainId }]) => { - const provider = new ethers.providers.JsonRpcProvider(rpc, { +export const PROVIDERS: Providers = Object.entries(CHAIN_CONFIG).reduce( + (acc, [, { rpc, name, evmChainId }]) => { + const provider = new ethers.providers.StaticJsonRpcProvider(rpc, { name, - chainId, + chainId: evmChainId, }); - const multicallProvider = new MulticallProvider(provider, chainId); + + const multicallProvider = new MulticallProvider(provider, evmChainId); return { ...acc, - [chainConfigKey]: { + [evmChainId]: { provider, multicallProvider, }, diff --git a/frontend/constants/react-query-keys.ts b/frontend/constants/react-query-keys.ts index 4760067d2..a089b827b 100644 --- a/frontend/constants/react-query-keys.ts +++ b/frontend/constants/react-query-keys.ts @@ -20,7 +20,7 @@ export const REACT_QUERY_KEYS = { ] as const, ALL_STAKING_CONTRACT_DETAILS: (chainId: number, stakingProgramId: string) => ['allStakingContractDetails', chainId, stakingProgramId] as const, - STAKING_PROGRAM_KEY: (chainId: number, serviceConfigId: number) => + STAKING_PROGRAM_KEY: (chainId: number, serviceConfigId: number = 0) => ['stakingProgram', chainId, serviceConfigId] as const, // wallets diff --git a/frontend/constants/urls.ts b/frontend/constants/urls.ts index ca4a3a6f3..ba2c4546a 100644 --- a/frontend/constants/urls.ts +++ b/frontend/constants/urls.ts @@ -31,14 +31,14 @@ export const GITHUB_API_LATEST_RELEASE: Url = 'https://api.github.com/repos/valory-xyz/olas-operate-app/releases/latest'; // explorers @note DO NOT END WITH `/` -export const OPTIMISM_EXPLORER_URL: Url = 'https://optimistic.etherscan.io'; +// export const OPTIMISM_EXPLORER_URL: Url = 'https://optimistic.etherscan.io'; export const GNOSIS_EXPLORER_URL: Url = 'https://gnosisscan.io'; export const EXPLORER_URL_BY_MIDDLEWARE_CHAIN: Record< string | MiddlewareChain, Url > = { - [MiddlewareChain.OPTIMISM]: OPTIMISM_EXPLORER_URL, + // [MiddlewareChain.OPTIMISM]: OPTIMISM_EXPLORER_URL, [MiddlewareChain.GNOSIS]: GNOSIS_EXPLORER_URL, }; diff --git a/frontend/context/BalanceProvider.tsx b/frontend/context/BalanceProvider.tsx index 2f4ad1404..805a6654b 100644 --- a/frontend/context/BalanceProvider.tsx +++ b/frontend/context/BalanceProvider.tsx @@ -1,3 +1,5 @@ +import { BigNumberish } from 'ethers'; +import { getAddress } from 'ethers/lib/utils'; import { Contract as MulticallContract } from 'ethers-multicall'; import { createContext, @@ -113,13 +115,30 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { setIsUpdatingBalances(true); try { - const [walletBalancesResult, stakedBalancesResult] = await Promise.all([ - getCrossChainWalletBalances(masterWallets), - getCrossChainStakedBalances(services), - ]); + const [walletBalancesResult, stakedBalancesResult] = + await Promise.allSettled([ + getCrossChainWalletBalances(masterWallets), + getCrossChainStakedBalances(services), + ]); + + console.log({ + walletBalancesResult, + stakedBalancesResult, + }); + + // parse the results + const walletBalances = + walletBalancesResult.status === 'fulfilled' + ? walletBalancesResult.value + : []; - setWalletBalances(walletBalancesResult); - setStakedBalances(stakedBalancesResult); + const stakedBalances = + stakedBalancesResult.status === 'fulfilled' + ? stakedBalancesResult.value + : []; + + setWalletBalances(walletBalances || []); + setStakedBalances(stakedBalances || []); setIsLoaded(true); } catch (error) { console.error('Error updating balances:', error); @@ -164,7 +183,7 @@ export const BalanceProvider = ({ children }: PropsWithChildren) => { export type WalletBalanceResult = { walletAddress: Address; - chainId: EvmChainId; + evmChainId: EvmChainId; symbol: TokenSymbol; isNative: boolean; balance: number; @@ -175,63 +194,97 @@ const getCrossChainWalletBalances = async ( ): Promise => { const balanceResults: WalletBalanceResult[] = []; - for (const [chainIdKey, { multicallProvider }] of Object.entries(PROVIDERS)) { - const chainId = Number(chainIdKey) as EvmChainId; - - const tokens = TOKEN_CONFIG[chainId]; - if (!tokens) continue; - - const relevantWallets = wallets.filter((wallet) => { - const isEoa = wallet.type === WalletType.EOA; - const isSafe = wallet.type === WalletType.Safe; - const isOnSameChain = isEoa || wallet.evmChainId === chainId; - return isEoa || (isSafe && isOnSameChain); - }); - - for (const [symbolKey, tokenConfig] of Object.entries(tokens)) { - const symbol = symbolKey as TokenSymbol; - - const isNative = tokenConfig.tokenType === TokenType.NativeGas; - const isErc20 = tokenConfig.tokenType === TokenType.Erc20; - - if (isNative) { - const nativeBalancePromises = relevantWallets.map(async (wallet) => { - const balance = await multicallProvider.getEthBalance(wallet.address); - return { - walletAddress: wallet.address, - chainId, - symbol, - isNative: true, - balance: Number(formatEther(balance)), - } as WalletBalanceResult; - }); + const providerEntries = Object.entries(PROVIDERS); - const nativeBalances = await Promise.all(nativeBalancePromises); - balanceResults.push(...nativeBalances); - } - - if (isErc20) { - const erc20Contract = new MulticallContract( - tokenConfig.address, - ERC20_BALANCE_OF_STRING_FRAGMENT, - ); + for (const [ + evmChainIdKey, + { multicallProvider, provider }, + ] of providerEntries) { + try { + const providerEvmChainId = +evmChainIdKey as EvmChainId; - const erc20Calls = relevantWallets.map((wallet) => - erc20Contract.balanceOf(wallet.address), - ); + const tokensOnChain = TOKEN_CONFIG[providerEvmChainId]; + // if (!tokensOnChain) continue; - const erc20Balances = await multicallProvider.all(erc20Calls); + const relevantWallets = wallets.filter((wallet) => { + const isEoa = wallet.type === WalletType.EOA; + const isSafe = wallet.type === WalletType.Safe; + const isOnProviderChain = + isEoa || (isSafe && wallet.evmChainId === providerEvmChainId); - const erc20Results = relevantWallets.map((wallet, index) => ({ - walletAddress: wallet.address, - chainId, - symbol, - isNative: false, - balance: Number(formatEther(erc20Balances[index])), - })) as WalletBalanceResult[]; + return isOnProviderChain; + }); - balanceResults.push(...erc20Results); + for (const { + tokenType, + symbol: tokenSymbol, + address: tokenAddress, + } of Object.values(tokensOnChain)) { + const isNative = tokenType === TokenType.NativeGas; + const isErc20 = tokenType === TokenType.Erc20; + + if (isNative) { + // get native balances for all relevant wallets + const nativeBalancePromises = relevantWallets.map< + Promise + >(({ address: walletAddress }) => + provider.getBalance(getAddress(walletAddress)), + ); + + const nativeBalances = await Promise.all(nativeBalancePromises).catch( + (e) => { + console.error('Error fetching native balances:', e); + return []; + }, + ); + + // add the results to the balance results + nativeBalances.forEach((balance, index) => + balanceResults.push({ + walletAddress: relevantWallets[index].address, + evmChainId: providerEvmChainId, + symbol: tokenSymbol, + isNative: true, + balance: Number(formatEther(balance)), + }), + ); + } + + if (isErc20) { + const erc20Contract = new MulticallContract( + tokenAddress, + ERC20_BALANCE_OF_STRING_FRAGMENT, + ); + + const erc20Calls = relevantWallets.map((wallet) => + erc20Contract.balanceOf(wallet.address), + ); + + if (providerEvmChainId === EvmChainId.Gnosis) { + console.log({ erc20Calls }); + } + + const erc20Balances = await multicallProvider.all(erc20Calls); + + if (providerEvmChainId === EvmChainId.Gnosis) { + console.log({ erc20Calls }); + } + + const erc20Results = relevantWallets.map( + ({ address: walletAddress }, index) => ({ + walletAddress, + evmChainId: providerEvmChainId, + symbol: tokenSymbol, + isNative: false, + balance: Number(formatEther(erc20Balances[index])), + }), + ) as WalletBalanceResult[]; + + balanceResults.push(...erc20Results); + } } + } catch (error) { + console.error('Error fetching balances for chain:', evmChainIdKey, error); } } diff --git a/frontend/context/MasterWalletProvider.tsx b/frontend/context/MasterWalletProvider.tsx index eed0c1756..60d7d7689 100644 --- a/frontend/context/MasterWalletProvider.tsx +++ b/frontend/context/MasterWalletProvider.tsx @@ -25,33 +25,34 @@ type MasterWalletContext = { UsePause; export const MasterWalletContext = createContext({ - masterEoa: undefined, - masterSafes: undefined, - masterWallets: undefined, paused: false, setPaused: () => {}, togglePaused: () => {}, }); const transformMiddlewareWalletResponse = ( - data: MiddlewareWalletResponse, + data: MiddlewareWalletResponse[], ): MasterWallets => { - const masterEoa: MasterEoa = { - address: data.address, - owner: WalletOwnerType.Master, - type: WalletType.EOA, - }; + const result: MasterWallets = []; - const masterSafes: MasterSafe[] = Object.entries(data.safes).map( - ([middlewareChain, address]) => ({ - address, - evmChainId: asEvmChainId(middlewareChain), + data.forEach((response) => { + result.push({ + address: response.address, owner: WalletOwnerType.Master, - type: WalletType.Safe, - }), - ); + type: WalletType.EOA, + }); + + Object.entries(response.safes).forEach(([middlewareChain, safeAddress]) => { + result.push({ + address: safeAddress, + evmChainId: asEvmChainId(middlewareChain), + owner: WalletOwnerType.Master, + type: WalletType.Safe, + }); + }); + }, []); - return [masterEoa, ...masterSafes]; + return result; }; export const MasterWalletProvider = ({ children }: PropsWithChildren) => { diff --git a/frontend/context/RewardProvider.tsx b/frontend/context/RewardProvider.tsx index efa61ce68..6149dc9db 100644 --- a/frontend/context/RewardProvider.tsx +++ b/frontend/context/RewardProvider.tsx @@ -32,24 +32,18 @@ export const RewardContext = createContext<{ minimumStakedAmountRequired?: number; updateRewards: () => Promise; }>({ - accruedServiceStakingRewards: undefined, - availableRewardsForEpoch: undefined, - availableRewardsForEpochEth: undefined, - isEligibleForRewards: undefined, - optimisticRewardsEarnedForEpoch: undefined, - minimumStakedAmountRequired: undefined, updateRewards: async () => {}, }); const currentAgent = AGENT_CONFIG.trader; // TODO: replace with dynamic agent selection -const currentChainId = GNOSIS_CHAIN_CONFIG.chainId; // TODO: replace with selectedAgentConfig.chainId +const currentChainId = GNOSIS_CHAIN_CONFIG.evmChainId; // TODO: replace with selectedAgentConfig.chainId /** * hook to fetch staking rewards details */ const useStakingRewardsDetails = () => { const { isOnline } = useContext(OnlineStatusContext); - const { activeStakingProgramId } = useContext(StakingProgramContext); + const { selectedStakingProgramId } = useContext(StakingProgramContext); const { selectedService } = useServices(); const { service } = useService(selectedService?.service_config_id); @@ -66,7 +60,7 @@ const useStakingRewardsDetails = () => { queryKey: REACT_QUERY_KEYS.REWARDS_KEY( currentChainId, serviceConfigId!, - activeStakingProgramId!, + selectedStakingProgramId!, multisig!, token!, ), @@ -75,7 +69,7 @@ const useStakingRewardsDetails = () => { { agentMultisigAddress: multisig!, serviceId: token!, - stakingProgramId: activeStakingProgramId!, + stakingProgramId: selectedStakingProgramId!, chainId: currentChainId, }, ); @@ -84,7 +78,7 @@ const useStakingRewardsDetails = () => { enabled: !!isOnline && !!serviceConfigId && - !!activeStakingProgramId && + !!selectedStakingProgramId && !!multisig && !!token, refetchInterval: isOnline ? FIVE_SECONDS_INTERVAL : false, diff --git a/frontend/context/ServicesProvider.tsx b/frontend/context/ServicesProvider.tsx index 694542f2b..33d2e4845 100644 --- a/frontend/context/ServicesProvider.tsx +++ b/frontend/context/ServicesProvider.tsx @@ -26,7 +26,7 @@ import { UsePause, usePause } from '@/hooks/usePause'; import { ServicesService } from '@/service/Services'; import { AgentConfig } from '@/types/Agent'; import { Service } from '@/types/Service'; -import { Maybe } from '@/types/Util'; +import { Maybe, Optional } from '@/types/Util'; import { asEvmChainId } from '@/utils/middlewareHelpers'; import { OnlineStatusContext } from './OnlineStatusProvider'; @@ -42,7 +42,7 @@ type ServicesContextType = { // number | EvmChainId, // MiddlewareServiceResponse[] // >; - selectService: (serviceUuid: string) => void; + selectService: (serviceConfigId: string) => void; selectedService?: Service; selectedAgentConfig: AgentConfig; selectedAgentType: AgentType; @@ -146,7 +146,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { // }, {}); // }, [isFetched, services]); - const serviceAddresses = useMemo(() => { + const serviceWallets: Optional = useMemo(() => { if (!isFetched) return; if (isEmpty(services)) return []; @@ -217,7 +217,7 @@ export const ServicesProvider = ({ children }: PropsWithChildren) => { >; isAllStakingContractDetailsRecordLoaded: boolean; - refetchActiveStakingContractDetails: () => Promise; + refetchSelectedStakingContractDetails: () => Promise; setIsPaused: Dispatch>; }; @@ -126,8 +126,7 @@ export const StakingContractDetailsContext = isPaused: false, isAllStakingContractDetailsRecordLoaded: false, isActiveStakingContractDetailsLoaded: false, - allStakingContractDetailsRecord: undefined, - refetchActiveStakingContractDetails: async () => {}, + refetchSelectedStakingContractDetails: async () => {}, setIsPaused: () => {}, }); @@ -141,39 +140,40 @@ export const StakingContractDetailsProvider = ({ const { selectedService, selectedAgentConfig } = useServices(); const { service } = useService(selectedService?.service_config_id); - const { activeStakingProgramId } = useContext(StakingProgramContext); + const { selectedStakingProgramId } = useContext(StakingProgramContext); const { - data: activeStakingContractDetails, + data: selectedStakingContractDetails, isLoading: isActiveStakingContractDetailsLoading, - refetch: refetchActiveStakingContract, + refetch, } = useStakingContractDetailsByStakingProgram({ serviceNftTokenId: - service?.chain_configs[asMiddlewareChain(selectedAgentConfig.evmHomeChainId)] - .chain_data.token, - stakingProgramId: activeStakingProgramId, + service?.chain_configs[ + asMiddlewareChain(selectedAgentConfig.evmHomeChainId) + ].chain_data.token, + stakingProgramId: selectedStakingProgramId, }); const { allStakingContractDetailsRecord, isAllStakingContractDetailsLoaded } = useAllStakingContractDetails(); - const refetchActiveStakingContractDetails = useCallback(async () => { - await refetchActiveStakingContract(); - }, [refetchActiveStakingContract]); + const refetchSelectedStakingContractDetails = useCallback(async () => { + await refetch(); + }, [refetch]); return ( {children} diff --git a/frontend/context/StakingProgramProvider.tsx b/frontend/context/StakingProgramProvider.tsx index 107794424..f5591e339 100644 --- a/frontend/context/StakingProgramProvider.tsx +++ b/frontend/context/StakingProgramProvider.tsx @@ -1,64 +1,74 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { isNil } from 'lodash'; import { createContext, PropsWithChildren, useCallback } from 'react'; -import { INITIAL_DEFAULT_STAKING_PROGRAM_IDS } from '@/config/stakingPrograms'; +import { DEFAULT_STAKING_PROGRAM_IDS } from '@/config/stakingPrograms'; import { FIVE_SECONDS_INTERVAL } from '@/constants/intervals'; import { REACT_QUERY_KEYS } from '@/constants/react-query-keys'; import { StakingProgramId } from '@/enums/StakingProgram'; import { useService } from '@/hooks/useService'; import { useServices } from '@/hooks/useServices'; -import { Maybe, Nullable } from '@/types/Util'; +import { Maybe, Nullable, Optional } from '@/types/Util'; export const StakingProgramContext = createContext<{ isActiveStakingProgramLoaded: boolean; - initialDefaultStakingProgramId: Maybe; - activeStakingProgramId: Maybe; + activeStakingProgramId?: Maybe; + defaultStakingProgramId: Nullable; + selectedStakingProgramId: Nullable; }>({ isActiveStakingProgramLoaded: false, - activeStakingProgramId: null, - initialDefaultStakingProgramId: null, + defaultStakingProgramId: null, + selectedStakingProgramId: null, }); /** * hook to get the active staking program id */ -const useGetActiveStakingProgramId = (serviceNftTokenId: Maybe) => { +const useGetActiveStakingProgramId = (serviceNftTokenId: Optional) => { const queryClient = useQueryClient(); - const { selectedAgentConfig } = useServices(); + const { selectedAgentConfig, isFetched: isServicesLoaded } = useServices(); - const { serviceApi, evmHomeChainId: homeChainId } = selectedAgentConfig; + const { serviceApi, evmHomeChainId } = selectedAgentConfig; const response = useQuery({ - queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY( - homeChainId, - serviceNftTokenId!, - ), + queryKey: REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(evmHomeChainId), queryFn: async () => { - const response = await serviceApi.getCurrentStakingProgramByServiceId( - serviceNftTokenId!, - homeChainId, - ); + if (!serviceNftTokenId) + return DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.evmHomeChainId]; + + const currentStakingProgramId = + await serviceApi.getCurrentStakingProgramByServiceId( + serviceNftTokenId, + evmHomeChainId, + ); + return ( - response || - INITIAL_DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.evmHomeChainId] + currentStakingProgramId || + DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.evmHomeChainId] ); }, - enabled: !!homeChainId && !!serviceNftTokenId, - refetchInterval: serviceNftTokenId ? FIVE_SECONDS_INTERVAL : false, + enabled: !isNil(evmHomeChainId) && isServicesLoaded, + refetchInterval: isServicesLoaded ? FIVE_SECONDS_INTERVAL : 0, }); const setActiveStakingProgramId = useCallback( (stakingProgramId: Nullable) => { - if (!serviceNftTokenId) return; - if (!stakingProgramId) return; + if (!serviceNftTokenId) + throw new Error( + 'serviceNftTokenId is required to set the active staking program id', + ); + if (!stakingProgramId) + throw new Error( + 'stakingProgramId is required to set the active staking program id', + ); // update the active staking program id in the cache queryClient.setQueryData( - REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(homeChainId, serviceNftTokenId), + REACT_QUERY_KEYS.STAKING_PROGRAM_KEY(evmHomeChainId, serviceNftTokenId), stakingProgramId, ); }, - [queryClient, homeChainId, serviceNftTokenId], + [queryClient, evmHomeChainId, serviceNftTokenId], ); return { ...response, setActiveStakingProgramId }; @@ -70,29 +80,32 @@ const useGetActiveStakingProgramId = (serviceNftTokenId: Maybe) => { * It also provides a method to update the active staking program id in state. */ export const StakingProgramProvider = ({ children }: PropsWithChildren) => { - const { - selectedService, - selectedAgentConfig, - isFetched: isLoaded, - } = useServices(); - const serviceConfigId = - isLoaded && selectedService ? selectedService?.service_config_id : ''; - const { service } = useService(serviceConfigId); + const { selectedService, selectedAgentConfig } = useServices(); + + const { service } = useService(selectedService?.service_config_id); const serviceNftTokenId = service?.chain_configs[service?.home_chain]?.chain_data?.token; - const { isLoading: isStakingProgramsLoading, data: activeStakingProgramId } = - useGetActiveStakingProgramId(serviceNftTokenId); + const { + isFetched: isActiveStakingProgramLoaded, + data: activeStakingProgramId, + } = useGetActiveStakingProgramId(serviceNftTokenId); + + const defaultStakingProgramId = + DEFAULT_STAKING_PROGRAM_IDS[selectedAgentConfig.evmHomeChainId]; + + const selectedStakingProgramId = isActiveStakingProgramLoaded + ? activeStakingProgramId || defaultStakingProgramId + : null; return ( {children} diff --git a/frontend/enums/Chain.ts b/frontend/enums/Chain.ts index ea6ae2d3e..2e0e5d1f8 100644 --- a/frontend/enums/Chain.ts +++ b/frontend/enums/Chain.ts @@ -1,7 +1,7 @@ export enum EvmChainId { Ethereum = 1, - Optimism = 100, - Gnosis = 10, + Optimism = 10, + Gnosis = 100, Base = 8453, } diff --git a/frontend/hooks/useBalanceContext.ts b/frontend/hooks/useBalanceContext.ts index 2cbcf149c..410bad47c 100644 --- a/frontend/hooks/useBalanceContext.ts +++ b/frontend/hooks/useBalanceContext.ts @@ -1,9 +1,11 @@ import { useContext, useMemo } from 'react'; +import { CHAIN_CONFIG } from '@/config/chains'; import { BalanceContext, WalletBalanceResult } from '@/context/BalanceProvider'; import { Optional } from '@/types/Util'; import { useService } from './useService'; +import { useServices } from './useServices'; import { useMasterWalletContext } from './useWallet'; export const useBalanceContext = () => useContext(BalanceContext); @@ -78,6 +80,7 @@ export const useServiceBalances = (serviceConfigId: string | undefined) => { * @note master safe addresses are deterministic, and should be the same */ export const useMasterBalances = () => { + const { selectedAgentConfig } = useServices(); const { masterSafes, masterEoa } = useMasterWalletContext(); const { walletBalances } = useBalanceContext(); @@ -92,8 +95,11 @@ export const useMasterBalances = () => { const masterSafeBalances = useMemo>( () => - walletBalances?.filter((balance) => - masterSafes?.find(({ address }) => balance.walletAddress === address), + walletBalances?.filter(({ walletAddress }) => + masterSafes?.find( + ({ address: masterSafeAddress }) => + walletAddress === masterSafeAddress, + ), ), [masterSafes, walletBalances], ); @@ -101,7 +107,7 @@ export const useMasterBalances = () => { const masterEoaBalances = useMemo>( () => walletBalances?.filter( - (balance) => balance.walletAddress === masterEoa?.address, + ({ walletAddress }) => walletAddress === masterEoa?.address, ), [masterEoa?.address, walletBalances], ); @@ -117,9 +123,38 @@ export const useMasterBalances = () => { return result; }, [masterEoaBalances, masterSafeBalances]); + const isMasterSafeLowOnNativeGas = useMemo(() => { + if (!masterSafeBalances) return; + if (!selectedAgentConfig?.evmHomeChainId) return; + + const homeChainNativeToken = + CHAIN_CONFIG[selectedAgentConfig?.evmHomeChainId].nativeToken; + + const nativeGasBalance = masterSafeBalances.find( + (walletBalance) => + walletBalance.isNative && + walletBalance.evmChainId === selectedAgentConfig.evmHomeChainId && + walletBalance.symbol === homeChainNativeToken.symbol, + ); + + if (!nativeGasBalance) return; + + const agentNativeGasRequirement = + selectedAgentConfig.agentSafeFundingRequirements?.[ + homeChainNativeToken.symbol + ]; + + return nativeGasBalance.balance < agentNativeGasRequirement; + }, [ + masterSafeBalances, + selectedAgentConfig.agentSafeFundingRequirements, + selectedAgentConfig.evmHomeChainId, + ]); + return { masterWalletBalances, masterSafeBalances, masterEoaBalances, + isMasterSafeLowOnNativeGas, }; }; diff --git a/frontend/hooks/useLogs.ts b/frontend/hooks/useLogs.ts index 6fdd6a713..51facad87 100644 --- a/frontend/hooks/useLogs.ts +++ b/frontend/hooks/useLogs.ts @@ -20,10 +20,8 @@ const useAddressesLogs = () => { isFetching: masterWalletsIsFetching, } = useMasterWalletContext(); - const { - masterSafesOwners: masterSafesOwners, - masterSafesOwnersIsPending: masterSafesOwnersIsPending, - } = useMultisigs(masterSafes); + const { masterSafesOwners, masterSafesOwnersIsFetched } = + useMultisigs(masterSafes); const backupEoas = useMemo>(() => { if (!masterEoa) return; @@ -47,7 +45,7 @@ const useAddressesLogs = () => { }, [masterSafesOwners, masterEoa]); return { - isLoaded: masterWalletsIsFetching && masterSafesOwnersIsPending, + isLoaded: masterWalletsIsFetching && masterSafesOwnersIsFetched, data: [ { masterEoa: masterEoa ?? 'undefined' }, { diff --git a/frontend/hooks/useMultisig.ts b/frontend/hooks/useMultisig.ts index 26aeed5ce..6cf7b0c37 100644 --- a/frontend/hooks/useMultisig.ts +++ b/frontend/hooks/useMultisig.ts @@ -21,7 +21,7 @@ export const useMultisig = (safe?: Safe) => { const { data: owners, isFetched: ownersIsFetched, - isPending: ownersIsPending, + // isPending: ownersIsPending, } = useQuery({ enabled: !isNil(safe), queryKey: safe ? REACT_QUERY_KEYS.MULTISIG_GET_OWNERS_KEY(safe) : [], @@ -39,7 +39,7 @@ export const useMultisig = (safe?: Safe) => { refetchInterval: FIVE_SECONDS_INTERVAL, }); - return { owners, ownersIsFetched, ownersIsPending }; + return { owners, ownersIsFetched }; }; type MultisigOwners = { diff --git a/frontend/hooks/useNeedsFunds.ts b/frontend/hooks/useNeedsFunds.ts index 51e8cea7a..78f052e52 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -6,6 +6,7 @@ import { STAKING_PROGRAMS } from '@/config/stakingPrograms'; import { getNativeTokenSymbol } from '@/config/tokens'; import { getServiceTemplate } from '@/constants/serviceTemplates'; import { TokenSymbol } from '@/enums/Token'; +import { asEvmChainId } from '@/utils/middlewareHelpers'; import { useBalanceContext, useMasterBalances } from './useBalanceContext'; import { useService } from './useService'; @@ -14,7 +15,9 @@ import { useStore } from './useStore'; export const useNeedsFunds = (serviceConfigId?: string) => { const { storeState } = useStore(); const { service } = useService(serviceConfigId); + const { isLoaded: isBalanceLoaded, walletBalances } = useBalanceContext(); + const { masterSafeBalances } = useMasterBalances(); const isInitialFunded = storeState?.isInitialFunded; @@ -38,28 +41,29 @@ export const useNeedsFunds = (serviceConfigId?: string) => { } = {}; Object.entries(serviceTemplate.configurations).forEach( - ([middlewareChainId, config]) => { + ([middlewareChain, config]) => { + const evmChainId = asEvmChainId(middlewareChain); + const templateStakingProgramId = - serviceTemplate.configurations[middlewareChainId].staking_program_id; + serviceTemplate.configurations[middlewareChain].staking_program_id; const serviceStakingProgramId = - service?.chain_configs[middlewareChainId as MiddlewareChain] - ?.chain_data?.user_params?.staking_program_id; + service?.chain_configs[middlewareChain as MiddlewareChain]?.chain_data + ?.user_params?.staking_program_id; const stakingProgramId = serviceStakingProgramId ?? templateStakingProgramId; if (!stakingProgramId) return; - if (!service?.chain_configs[middlewareChainId as MiddlewareChain]) - return; + if (!service?.chain_configs[middlewareChain as MiddlewareChain]) return; const gasEstimate = config.monthly_gas_estimate; const monthlyGasEstimate = Number(formatUnits(`${gasEstimate}`, 18)); const minimumStakedAmountRequired = - STAKING_PROGRAMS[+middlewareChainId]?.[stakingProgramId] + STAKING_PROGRAMS[evmChainId]?.[stakingProgramId] ?.stakingRequirements?.[TokenSymbol.OLAS] || 0; - const nativeTokenSymbol = getNativeTokenSymbol(+middlewareChainId); + const nativeTokenSymbol = getNativeTokenSymbol(evmChainId); - results[+middlewareChainId] = { + results[evmChainId] = { [TokenSymbol.OLAS]: +formatEther(minimumStakedAmountRequired), [nativeTokenSymbol]: +formatEther(monthlyGasEstimate), // TODO: extend with any further erc20s.. @@ -76,11 +80,11 @@ export const useNeedsFunds = (serviceConfigId?: string) => { const nativeBalancesByChain = walletBalances.reduce<{ [chainId: number]: number; - }>((acc, { symbol, balance, chainId }) => { - if (getNativeTokenSymbol(chainId) !== symbol) return acc; + }>((acc, { symbol, balance, evmChainId }) => { + if (getNativeTokenSymbol(evmChainId) !== symbol) return acc; - if (!acc[chainId]) acc[chainId] = 0; - acc[chainId] += balance; + if (!acc[evmChainId]) acc[evmChainId] = 0; + acc[evmChainId] += balance; return acc; }, {}); @@ -103,11 +107,11 @@ export const useNeedsFunds = (serviceConfigId?: string) => { const olasBalancesByChain = masterSafeBalances.reduce<{ [chainId: number]: number; - }>((acc, { symbol, balance, chainId }) => { + }>((acc, { symbol, balance, evmChainId }) => { if (TokenSymbol.OLAS !== symbol) return acc; - if (!acc[chainId]) acc[chainId] = 0; - acc[chainId] += balance; + if (!acc[evmChainId]) acc[evmChainId] = 0; + acc[evmChainId] += balance; return acc; }, {}); diff --git a/frontend/hooks/useStakingContractDetails.ts b/frontend/hooks/useStakingContractDetails.ts index 1b53630e7..89c348912 100644 --- a/frontend/hooks/useStakingContractDetails.ts +++ b/frontend/hooks/useStakingContractDetails.ts @@ -6,28 +6,8 @@ import { StakingProgramId } from '@/enums/StakingProgram'; import { StakingState } from '@/types/Autonolas'; import { Maybe } from '@/types/Util'; -import { useServices } from './useServices'; - -export const useStakingContractContext = () => { - const { - activeStakingContractDetails, - isPaused, - isAllStakingContractDetailsRecordLoaded, - allStakingContractDetailsRecord, - refetchActiveStakingContractDetails, - setIsPaused, - isActiveStakingContractDetailsLoaded, - } = useContext(StakingContractDetailsContext); - return { - isActiveStakingContractDetailsLoaded, - activeStakingContractDetails, - isPaused, - isAllStakingContractDetailsRecordLoaded, - allStakingContractDetailsRecord, - refetchActiveStakingContractDetails, - setIsPaused, - }; -}; +export const useStakingContractContext = () => + useContext(StakingContractDetailsContext); /** * Returns ACTIVE staking contract details @@ -38,24 +18,25 @@ export const useStakingContractContext = () => { export const useActiveStakingContractInfo = () => { const { activeStakingContractDetails, - isActiveStakingContractDetailsLoaded: isActiveStakingContractDetailsLoaded, - allStakingContractDetailsRecord, - refetchActiveStakingContractDetails, - isPaused, - setIsPaused, + isActiveStakingContractDetailsLoaded, + // allStakingContractDetailsRecord, + // refetchActiveStakingContractDetails, + // isPaused, + // setIsPaused, } = useStakingContractContext(); - const { selectedService } = useServices(); - - // TODO: find a better way to handle this, currently stops react lifecycle hooks being implemented below it - if (!selectedService || !activeStakingContractDetails) { - return { - allStakingContractDetailsRecord, - refetchActiveStakingContractDetails, - isPaused, - setIsPaused, - }; - } + // const { selectedService } = useServices(); + + // // TODO: find a better way to handle this, currently stops react lifecycle hooks being implemented below it + // if (!selectedService || !activeStakingContractDetails) { + // return { + // allStakingContractDetailsRecord, + // refetchActiveStakingContractDetails, + // isPaused, + // setIsPaused, + // isActiveStakingContractDetailsLoaded, + // }; + // } const { serviceStakingState, diff --git a/frontend/hooks/useStakingProgram.ts b/frontend/hooks/useStakingProgram.ts index 34680c827..1a1457320 100644 --- a/frontend/hooks/useStakingProgram.ts +++ b/frontend/hooks/useStakingProgram.ts @@ -3,10 +3,8 @@ import { useContext, useMemo } from 'react'; import { STAKING_PROGRAM_ADDRESS, STAKING_PROGRAMS, - StakingProgramConfig, } from '@/config/stakingPrograms'; import { StakingProgramContext } from '@/context/StakingProgramProvider'; -import { StakingProgramId } from '@/enums/StakingProgram'; import { Address } from '@/types/Address'; import { Nullable } from '@/types/Util'; @@ -19,36 +17,17 @@ export const useStakingProgram = () => { const { isActiveStakingProgramLoaded, activeStakingProgramId, - initialDefaultStakingProgramId, + defaultStakingProgramId, + selectedStakingProgramId, } = useContext(StakingProgramContext); - const { selectedAgentConfig } = useServices(); - const { evmHomeChainId: homeChainId } = selectedAgentConfig; - - const allStakingProgramsKeys = Object.keys(STAKING_PROGRAMS[homeChainId]); - const allStakingProgramNameAddressPair = STAKING_PROGRAM_ADDRESS[homeChainId]; - // TODO: refactor to support allStakingPrograms, previously this was intended solely for the active staking program const allStakingProgramsMeta = useMemo(() => { - if (!isActiveStakingProgramLoaded) return null; - if (!activeStakingProgramId) return null; - if (activeStakingProgramId.length === 0) return null; + return STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId]; + }, [selectedAgentConfig.evmHomeChainId]); - return (allStakingProgramsKeys as StakingProgramId[]).reduce( - (acc, programId) => { - if (activeStakingProgramId.includes(programId)) { - acc[programId] = STAKING_PROGRAMS[homeChainId][programId]; - } - return acc; - }, - {} as Record, - ); - }, [ - homeChainId, - isActiveStakingProgramLoaded, - allStakingProgramsKeys, - activeStakingProgramId, - ]); + const allStakingProgramNameAddressPair = + STAKING_PROGRAM_ADDRESS[selectedAgentConfig.evmHomeChainId]; const activeStakingProgramMeta = useMemo(() => { if (!isActiveStakingProgramLoaded) return null; @@ -67,15 +46,35 @@ export const useStakingProgram = () => { return allStakingProgramNameAddressPair[activeStakingProgramId]; }, [allStakingProgramNameAddressPair, activeStakingProgramId]); - return { - initialDefaultStakingProgramId, + const defaultStakingProgramMeta = useMemo(() => { + if (!defaultStakingProgramId) return null; + return STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][ + defaultStakingProgramId + ]; + }, [defaultStakingProgramId, selectedAgentConfig.evmHomeChainId]); + + const selectedStakingProgramMeta = useMemo(() => { + if (!selectedStakingProgramId) return null; + return STAKING_PROGRAMS[selectedAgentConfig.evmHomeChainId][ + selectedStakingProgramId + ]; + }, [selectedAgentConfig.evmHomeChainId, selectedStakingProgramId]); + return { // active staking program isActiveStakingProgramLoaded, activeStakingProgramId, activeStakingProgramAddress, activeStakingProgramMeta, + // default staking program + defaultStakingProgramId, + defaultStakingProgramMeta, + + // selected staking program id + selectedStakingProgramId, + selectedStakingProgramMeta, + // all staking programs allStakingProgramIds: Object.keys(allStakingProgramNameAddressPair), allStakingProgramAddress: Object.values(allStakingProgramNameAddressPair), diff --git a/frontend/service/Wallet.ts b/frontend/service/Wallet.ts index b8a29704b..700c8b58e 100644 --- a/frontend/service/Wallet.ts +++ b/frontend/service/Wallet.ts @@ -9,7 +9,7 @@ const getWallets = async () => fetch(`${BACKEND_URL}/wallet`).then((res) => { if (res.ok) return res.json(); throw new Error('Failed to get wallets'); - }) as Promise; + }) as Promise; const createEoa = async () => fetch(`${BACKEND_URL}/wallet`, { diff --git a/frontend/utils/truncate.ts b/frontend/utils/truncate.ts index c43325abf..e60935f76 100644 --- a/frontend/utils/truncate.ts +++ b/frontend/utils/truncate.ts @@ -1,4 +1,7 @@ +import { NA } from '@/constants/symbols'; import { Address } from '@/types/Address'; export const truncateAddress = (address: Address, length = 4) => - `${address?.substring(0, 2 + length)}...${address?.substring(address.length - length, address.length)}`; + typeof address === 'string' + ? `${address?.substring(0, 2 + length)}...${address?.substring(address.length - length, address.length)}` + : NA; diff --git a/scripts/js/tenderly-optimus-fund-master-safes.js b/scripts/js/tenderly-optimus-fund-master-safes.js index 626e0280e..71cf9887a 100644 --- a/scripts/js/tenderly-optimus-fund-master-safes.js +++ b/scripts/js/tenderly-optimus-fund-master-safes.js @@ -10,37 +10,36 @@ require('dotenv').config(); const fs = require('fs'); -const operateEthereumJson = fs.readFileSync('.operate/wallets/ethereum.json'); +const operateEthereumJson = fs.readFileSync('./.operate/wallets/ethereum.json'); const operateEthereum = JSON.parse(operateEthereumJson); -console.log(operateEthereum) +const masterSafeAddress = Object.values(operateEthereum.safes)[0]; // assuming all safe addresses are the same -const masterSafeAddress = operateEthereum.safes['4']; // assuming all safe addresses are the same - -const setBalance = async (masterSafeAddress, rpc) => fetch(rpc, { +const setBalance = async (address, rpc) => fetch(rpc, { method: 'POST', body: JSON.stringify({ jsonrpc: '2.0', method: 'tenderly_setBalance', params: [ - masterSafeAddress, + address, "0x3635C9ADC5DEA00000" ] }), -}).then(() => console.log(`Successfully set balance for ${masterSafeAddress} on ${rpc}`)) +}).then(() => console.log(`Successfully set balance for ${address} on ${rpc}`)) -const setErc20Balance = async (erc20Address, masterSafeAddress, rpc) => fetch(rpc, { +const setErc20Balance = async (erc20Address, address, rpc) => fetch(rpc, { method: 'POST', body: JSON.stringify({ jsonrpc: '2.0', method: 'tenderly_setERC20Balance', params: [ erc20Address, - masterSafeAddress, + address, "0x3635C9ADC5DEA00000" - ] + ], + id: "1234" }), -}).then(() => console.log(`Successfully set ERC20 balance for ${masterSafeAddress} on ${rpc}`)) +}).then((e) => console.log(`Successfully set ERC20 balance for ${address} on ${rpc}\n ${JSON.stringify(e)}`)) const main = async () => { const rpcs = { @@ -52,24 +51,59 @@ const main = async () => { const erc20Addresses = { olas: { - gnosis: "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f", + gnosis: "0xce11e14225575945b8e6dc0d4f2dd4c570f79d9f", optimism: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527", ethereum: - "0x0001A500A6B18995B03f44bb040A5fFc28E45CB0", + "0x0001a500a6b18995b03f44bb040a5ffc28e45cb0", base: - "0x4B1a99467a284CC690e3237bc69105956816F762" + "0x54330d28ca3357F294334BDC454a032e7f353416" }, usdc: { ethereum: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" } } + // ETH on all await Promise.all(Object.values(rpcs).map(rpc => setBalance(masterSafeAddress, rpc))); + + // check eth on all + await Promise.all(Object.entries(rpcs).map(([chain, rpc]) => + fetch(rpc, { + method: 'POST', + body: JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_getBalance', + params: [ + masterSafeAddress, + 'latest' + ], + id: 1 + }), + }).then(async (res) => JSON.stringify(({... await res.json(), chain}), null, 0)).then(console.log) + )); // ERC20s - await setErc20Balance(erc20Addresses.usdc.ethereum, masterSafeAddress, rpcs.ethereum) - await setErc20Balance(erc20Addresses.olas.optimism, masterSafeAddress, rpcs.optimism) + await Promise.all(Object.entries(erc20Addresses.olas).map(([chain, address]) => setErc20Balance(address, masterSafeAddress, rpcs[chain]))); + + // check erc20s + await Promise.all(Object.entries(erc20Addresses.olas).map(([chain, address]) => + fetch(rpcs[chain], { + method: 'POST', + body: JSON.stringify({ + jsonrpc: '2.0', + method: 'eth_call', + params: [ + { + to: address, + data: `0x70a082310000000000000000${masterSafeAddress.slice(2)}` + }, + 'latest' + ], + id: 1 + }), + }).then(async (res) => JSON.stringify(({... await res.json(), chain}), null, 0)).then(console.log) + )); } main() \ No newline at end of file From bb9b2983058fa71cfe0b3a987baf701915b82609 Mon Sep 17 00:00:00 2001 From: truemiller Date: Mon, 25 Nov 2024 03:14:26 +0000 Subject: [PATCH 386/463] fix: further fixes for refactor --- .../header/AgentButton/AgentButton.tsx | 5 +- .../AgentButton/AgentNotRunningButton.tsx | 213 +++++++++++------- .../NoAvailableSlotsOnTheContract.tsx | 2 +- .../sections/RewardsSection/RewardsStreak.tsx | 5 +- .../StakingContractSection/MigrateButton.tsx | 14 +- .../components/YourWalletPage/YourAgent.tsx | 2 +- frontend/constants/react-query-keys.ts | 2 +- frontend/context/BalanceProvider.tsx | 34 +-- .../StakingContractDetailsProvider.tsx | 37 +-- frontend/hooks/useNotifyOnNewEpoch.ts | 2 +- frontend/hooks/useRewardsHistory.ts | 8 +- frontend/hooks/useService.ts | 4 +- frontend/hooks/useStakingContractDetails.ts | 10 +- frontend/service/Services.ts | 6 +- frontend/service/agents/PredictTrader.ts | 2 +- 15 files changed, 198 insertions(+), 148 deletions(-) diff --git a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx index 7b9705df7..b80218086 100644 --- a/frontend/components/MainPage/header/AgentButton/AgentButton.tsx +++ b/frontend/components/MainPage/header/AgentButton/AgentButton.tsx @@ -27,11 +27,11 @@ export const AgentButton = () => { const { isEligibleForStaking, isAgentEvicted, - isActiveStakingContractDetailsLoaded, + isSelectedStakingContractDetailsLoaded, } = useActiveStakingContractInfo(); const button = useMemo(() => { - if (!isServicesLoaded || !isActiveStakingContractDetailsLoaded) { + if (!isServicesLoaded || !isSelectedStakingContractDetailsLoaded) { return (