From 8c495bbd27013c1c992324e5d63de75e3828cb22 Mon Sep 17 00:00:00 2001 From: OjusWiZard Date: Thu, 14 Nov 2024 02:58:49 +0530 Subject: [PATCH] Refactor: ChainType and LedgerType Signed-off-by: OjusWiZard --- api.md | 18 +-- frontend/client/enums.ts | 14 +- frontend/client/types.ts | 2 +- .../components/MainPage/header/constants.ts | 2 +- .../SetupPage/Create/SetupCreateSafe.tsx | 14 +- .../SetupPage/Create/SetupEoaFunding.tsx | 6 +- .../components/YourWalletPage/YourAgent.tsx | 2 +- frontend/constants/contractAddresses.ts | 8 +- frontend/constants/serviceTemplates.ts | 12 +- frontend/hooks/useNeedsFunds.ts | 2 +- frontend/hooks/useServices.ts | 8 +- frontend/service/Services.ts | 4 +- 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 +- 24 files changed, 357 insertions(+), 332 deletions(-) diff --git a/api.md b/api.md index 4ed49d22..60eac290 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 08bc12a5..c0595315 100644 --- a/frontend/client/enums.ts +++ b/frontend/client/enums.ts @@ -6,13 +6,13 @@ export enum Action { } 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 Ledger { diff --git a/frontend/client/types.ts b/frontend/client/types.ts index a02585c5..3237b76d 100644 --- a/frontend/client/types.ts +++ b/frontend/client/types.ts @@ -63,7 +63,7 @@ export type ServiceTemplate = { image: string; description: 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/MainPage/header/constants.ts b/frontend/components/MainPage/header/constants.ts index af064963..ec896195 100644 --- a/frontend/components/MainPage/header/constants.ts +++ b/frontend/components/MainPage/header/constants.ts @@ -5,7 +5,7 @@ import { SERVICE_TEMPLATES } from '@/constants/serviceTemplates'; export const requiredGas = Number( formatUnits( - `${SERVICE_TEMPLATES[0].configurations[CHAINS.OPTIMISM.chainId].monthly_gas_estimate}`, + `${SERVICE_TEMPLATES[0].configurations[CHAINS.OPTIMISM.middlewareChain].monthly_gas_estimate}`, 18, ), ); diff --git a/frontend/components/SetupPage/Create/SetupCreateSafe.tsx b/frontend/components/SetupPage/Create/SetupCreateSafe.tsx index d222c868..f13f418e 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 da81b7dd..15c7da19 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 8105e9d5..080c12a3 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/constants/contractAddresses.ts b/frontend/constants/contractAddresses.ts index b5fa380b..75f3c19e 100644 --- a/frontend/constants/contractAddresses.ts +++ b/frontend/constants/contractAddresses.ts @@ -19,13 +19,13 @@ Object.entries(CHAINS).forEach(([, { chainId }]) => { setMulticallAddress(chainId, MULTICALL_CONTRACT_ADDRESS); }); -export const SERVICE_REGISTRY_L2_CONTRACT_ADDRESS: Record = { +export const SERVICE_REGISTRY_L2_CONTRACT_ADDRESS: Record = { // [MiddlewareChain.GNOSIS]: '0x9338b5153AE39BB89f50468E608eD9d764B755fD', [MiddlewareChain.OPTIMISM]: '0x3d77596beb0f130a4415df3D2D8232B3d3D31e44', }; export const SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT_ADDRESS: Record< - number, + MiddlewareChain.OPTIMISM, Address > = { // [MiddlewareChain.GNOSIS]: '0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8', @@ -33,7 +33,7 @@ export const SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT_ADDRESS: Record< }; export const SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES: Record< - number, + MiddlewareChain.OPTIMISM, Record > = { // [Chain.GNOSIS]: { @@ -81,7 +81,7 @@ export const SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES: Record< // }; export const STAKING_ACTIVITY_CHECKER_CONTRACT_ADDRESS: Record< - number, + MiddlewareChain.OPTIMISM, Address > = { [MiddlewareChain.OPTIMISM]: '0x7Fd1F4b764fA41d19fe3f63C85d12bf64d2bbf68', diff --git a/frontend/constants/serviceTemplates.ts b/frontend/constants/serviceTemplates.ts index eabaf05a..f78f1a0b 100644 --- a/frontend/constants/serviceTemplates.ts +++ b/frontend/constants/serviceTemplates.ts @@ -11,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: '100', + home_chain: 'gnosis', configurations: { - 100: { + [CHAINS.GNOSIS.middlewareChain]: { staking_program_id: StakingProgramId.OptimusAlpha, // default, may be overwritten nft: 'bafybeig64atqaladigoc3ds4arltdu63wkdrk3gesjfvnfdmz35amv7faq', rpc: 'http://localhost:8545', @@ -105,9 +105,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 +122,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 +137,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 16e3a832..57c88a50 100644 --- a/frontend/hooks/useNeedsFunds.ts +++ b/frontend/hooks/useNeedsFunds.ts @@ -25,7 +25,7 @@ export const useNeedsFunds = () => { const serviceFundRequirements = useMemo(() => { const gasEstimate = - serviceTemplate.configurations[CHAINS.OPTIMISM.chainId] + serviceTemplate.configurations[CHAINS.OPTIMISM.middlewareChain] .monthly_gas_estimate; const monthlyGasEstimate = Number(formatUnits(`${gasEstimate}`, 18)); const minimumStakedAmountRequired = diff --git a/frontend/hooks/useServices.ts b/frontend/hooks/useServices.ts index 36aed02a..f79a7708 100644 --- a/frontend/hooks/useServices.ts +++ b/frontend/hooks/useServices.ts @@ -33,11 +33,11 @@ const checkServiceIsFunded = async ( Object.assign(acc, { [address]: instances.includes(address) ? balances[address] > - serviceTemplate.configurations[CHAINS.OPTIMISM.chainId] - .fund_requirements.agent + serviceTemplate.configurations[CHAINS.OPTIMISM.middlewareChain] + .fund_requirements.agent : balances[address] > - serviceTemplate.configurations[CHAINS.OPTIMISM.chainId] - .fund_requirements.safe, + serviceTemplate.configurations[CHAINS.OPTIMISM.middlewareChain] + .fund_requirements.safe, }), {}, ); diff --git a/frontend/service/Services.ts b/frontend/service/Services.ts index cfbabf7c..7424d70c 100644 --- a/frontend/service/Services.ts +++ b/frontend/service/Services.ts @@ -62,8 +62,8 @@ const createService = async ({ ...serviceTemplate, deploy, configurations: { - [CHAINS.OPTIMISM.chainId]: { - ...serviceTemplate.configurations[CHAINS.OPTIMISM.chainId], + [CHAINS.OPTIMISM.middlewareChain]: { + ...serviceTemplate.configurations[CHAINS.OPTIMISM.middlewareChain], staking_program_id: stakingProgramId, rpc: `${process.env.OPTIMISM_RPC}`, use_mech_marketplace: useMechMarketplace, diff --git a/operate/cli.py b/operate/cli.py index cf5ac763..91a7b640 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 7238257f..76cbf012 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 c1810de8..9d15b866 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 36482a0e..a7194806 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 a82db9ad..b0ddc690 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 a20ff505..1a498e11 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 a2d79350..5444d4ba 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 9685cc49..8baa0e3b 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 e3ec758e..fa0a1cf1 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 5d5a47f7..78336f6d 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 331c61eb..4076c9bb 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 7c9e4b3b..cf639bf4 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