olas-operate-middleware 0.8.2__py3-none-any.whl → 0.10.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {olas_operate_middleware-0.8.2.dist-info → olas_operate_middleware-0.10.0.dist-info}/METADATA +2 -2
- {olas_operate_middleware-0.8.2.dist-info → olas_operate_middleware-0.10.0.dist-info}/RECORD +34 -34
- operate/bridge/bridge_manager.py +5 -6
- operate/bridge/providers/native_bridge_provider.py +1 -1
- operate/bridge/providers/provider.py +4 -5
- operate/bridge/providers/relay_provider.py +1 -1
- operate/cli.py +128 -48
- operate/constants.py +9 -9
- operate/keys.py +26 -14
- operate/ledger/__init__.py +4 -4
- operate/ledger/profiles.py +9 -11
- operate/migration.py +326 -0
- operate/operate_types.py +9 -27
- operate/quickstart/analyse_logs.py +3 -6
- operate/quickstart/claim_staking_rewards.py +1 -4
- operate/quickstart/reset_configs.py +0 -3
- operate/quickstart/reset_password.py +0 -3
- operate/quickstart/reset_staking.py +3 -5
- operate/quickstart/run_service.py +5 -7
- operate/quickstart/stop_service.py +3 -4
- operate/quickstart/terminate_on_chain_service.py +1 -4
- operate/quickstart/utils.py +4 -7
- operate/resource.py +37 -5
- operate/services/deployment_runner.py +170 -38
- operate/services/health_checker.py +5 -8
- operate/services/manage.py +103 -164
- operate/services/protocol.py +5 -5
- operate/services/service.py +42 -242
- operate/utils/__init__.py +44 -0
- operate/utils/gnosis.py +25 -17
- operate/wallet/master.py +20 -24
- {olas_operate_middleware-0.8.2.dist-info → olas_operate_middleware-0.10.0.dist-info}/LICENSE +0 -0
- {olas_operate_middleware-0.8.2.dist-info → olas_operate_middleware-0.10.0.dist-info}/WHEEL +0 -0
- {olas_operate_middleware-0.8.2.dist-info → olas_operate_middleware-0.10.0.dist-info}/entry_points.txt +0 -0
operate/ledger/__init__.py
CHANGED
|
@@ -46,7 +46,7 @@ PUBLIC_RPCS = {
|
|
|
46
46
|
Chain.SOLANA: SOLANA_PUBLIC_RPC,
|
|
47
47
|
Chain.BASE: BASE_PUBLIC_RPC,
|
|
48
48
|
Chain.CELO: CELO_PUBLIC_RPC,
|
|
49
|
-
Chain.
|
|
49
|
+
Chain.OPTIMISM: OPTIMISM_PUBLIC_RPC,
|
|
50
50
|
Chain.MODE: MODE_PUBLIC_RPC,
|
|
51
51
|
}
|
|
52
52
|
|
|
@@ -56,7 +56,7 @@ DEFAULT_RPCS = {
|
|
|
56
56
|
Chain.SOLANA: SOLANA_RPC,
|
|
57
57
|
Chain.BASE: BASE_RPC,
|
|
58
58
|
Chain.CELO: CELO_RPC,
|
|
59
|
-
Chain.
|
|
59
|
+
Chain.OPTIMISM: OPTIMISM_RPC,
|
|
60
60
|
Chain.MODE: MODE_RPC,
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -67,7 +67,7 @@ CURRENCY_DENOMS = {
|
|
|
67
67
|
Chain.SOLANA: "SOL",
|
|
68
68
|
Chain.BASE: "ETH",
|
|
69
69
|
Chain.CELO: "CELO",
|
|
70
|
-
Chain.
|
|
70
|
+
Chain.OPTIMISM: "ETH",
|
|
71
71
|
Chain.MODE: "ETH",
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -78,7 +78,7 @@ CURRENCY_SMALLEST_UNITS = {
|
|
|
78
78
|
Chain.SOLANA: "Lamport",
|
|
79
79
|
Chain.BASE: "Wei",
|
|
80
80
|
Chain.CELO: "Wei",
|
|
81
|
-
Chain.
|
|
81
|
+
Chain.OPTIMISM: "Wei",
|
|
82
82
|
Chain.MODE: "Wei",
|
|
83
83
|
}
|
|
84
84
|
|
operate/ledger/profiles.py
CHANGED
|
@@ -21,12 +21,10 @@
|
|
|
21
21
|
|
|
22
22
|
import typing as t
|
|
23
23
|
|
|
24
|
-
from operate.constants import ZERO_ADDRESS
|
|
24
|
+
from operate.constants import NO_STAKING_PROGRAM_ID, ZERO_ADDRESS
|
|
25
25
|
from operate.operate_types import Chain, ContractAddresses
|
|
26
26
|
|
|
27
27
|
|
|
28
|
-
NO_STAKING_PROGRAM_ID = "no_staking"
|
|
29
|
-
|
|
30
28
|
CONTRACTS: t.Dict[Chain, ContractAddresses] = {
|
|
31
29
|
Chain.GNOSIS: ContractAddresses(
|
|
32
30
|
{
|
|
@@ -38,7 +36,7 @@ CONTRACTS: t.Dict[Chain, ContractAddresses] = {
|
|
|
38
36
|
"multisend": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D",
|
|
39
37
|
}
|
|
40
38
|
),
|
|
41
|
-
Chain.
|
|
39
|
+
Chain.OPTIMISM: ContractAddresses(
|
|
42
40
|
{
|
|
43
41
|
"service_manager": "0xFbBEc0C8b13B38a9aC0499694A69a10204c5E2aB",
|
|
44
42
|
"service_registry": "0x3d77596beb0f130a4415df3D2D8232B3d3D31e44",
|
|
@@ -123,7 +121,7 @@ STAKING: t.Dict[Chain, t.Dict[str, str]] = {
|
|
|
123
121
|
"marketplace_demand_alpha_1": "0x9d6e7aB0B5B48aE5c146936147C639fEf4575231",
|
|
124
122
|
"marketplace_demand_alpha_2": "0x9fb17E549FefcCA630dd92Ea143703CeE4Ea4340",
|
|
125
123
|
},
|
|
126
|
-
Chain.
|
|
124
|
+
Chain.OPTIMISM: {
|
|
127
125
|
"optimus_alpha_1": "0x88996bbdE7f982D93214881756840cE2c77C4992",
|
|
128
126
|
"optimus_alpha_2": "0xBCA056952D2A7a8dD4A002079219807CFDF9fd29",
|
|
129
127
|
"optimus_alpha_3": "0x0f69f35652B1acdbD769049334f1AC580927E139",
|
|
@@ -170,7 +168,7 @@ DEFAULT_PRIORITY_MECH = { # maps mech marketplace address to its default priori
|
|
|
170
168
|
# ERC20 token addresses
|
|
171
169
|
OLAS: t.Dict[Chain, str] = {
|
|
172
170
|
Chain.GNOSIS: "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f",
|
|
173
|
-
Chain.
|
|
171
|
+
Chain.OPTIMISM: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527",
|
|
174
172
|
Chain.BASE: "0x54330d28ca3357F294334BDC454a032e7f353416",
|
|
175
173
|
Chain.ETHEREUM: "0x0001A500A6B18995B03f44bb040A5fFc28E45CB0",
|
|
176
174
|
Chain.MODE: "0xcfD1D50ce23C46D3Cf6407487B2F8934e96DC8f9",
|
|
@@ -178,7 +176,7 @@ OLAS: t.Dict[Chain, str] = {
|
|
|
178
176
|
|
|
179
177
|
USDC: t.Dict[Chain, str] = {
|
|
180
178
|
Chain.GNOSIS: "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83",
|
|
181
|
-
Chain.
|
|
179
|
+
Chain.OPTIMISM: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
|
|
182
180
|
Chain.BASE: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
183
181
|
Chain.ETHEREUM: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
|
|
184
182
|
Chain.MODE: "0xd988097fb8612cc24eeC14542bC03424c656005f",
|
|
@@ -186,7 +184,7 @@ USDC: t.Dict[Chain, str] = {
|
|
|
186
184
|
|
|
187
185
|
WRAPPED_NATIVE_ASSET = {
|
|
188
186
|
Chain.GNOSIS: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
|
|
189
|
-
Chain.
|
|
187
|
+
Chain.OPTIMISM: "0x4200000000000000000000000000000000000006",
|
|
190
188
|
Chain.BASE: "0x4200000000000000000000000000000000000006",
|
|
191
189
|
Chain.ETHEREUM: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
|
|
192
190
|
Chain.MODE: "0x4200000000000000000000000000000000000006",
|
|
@@ -209,7 +207,7 @@ DEFAULT_NEW_SAFE_FUNDS: t.Dict[Chain, t.Dict[str, int]] = {
|
|
|
209
207
|
Chain.MODE: {
|
|
210
208
|
ZERO_ADDRESS: int(1e15 / 4),
|
|
211
209
|
},
|
|
212
|
-
Chain.
|
|
210
|
+
Chain.OPTIMISM: {
|
|
213
211
|
ZERO_ADDRESS: int(1e15 / 4),
|
|
214
212
|
},
|
|
215
213
|
}
|
|
@@ -219,7 +217,7 @@ DEFAULT_MASTER_EOA_FUNDS = {
|
|
|
219
217
|
Chain.ETHEREUM: {ZERO_ADDRESS: 20_000_000_000_000_000},
|
|
220
218
|
Chain.GNOSIS: {ZERO_ADDRESS: 1_500_000_000_000_000_000},
|
|
221
219
|
Chain.MODE: {ZERO_ADDRESS: 500_000_000_000_000},
|
|
222
|
-
Chain.
|
|
220
|
+
Chain.OPTIMISM: {ZERO_ADDRESS: 5_000_000_000_000_000},
|
|
223
221
|
}
|
|
224
222
|
|
|
225
223
|
EXPLORER_URL = {
|
|
@@ -239,7 +237,7 @@ EXPLORER_URL = {
|
|
|
239
237
|
"tx": "https://modescan.io/tx/{tx_hash}",
|
|
240
238
|
"address": "https://modescan.io/address/{address}",
|
|
241
239
|
},
|
|
242
|
-
Chain.
|
|
240
|
+
Chain.OPTIMISM: {
|
|
243
241
|
"tx": "https://optimistic.etherscan.io/tx/{tx_hash}",
|
|
244
242
|
"address": "https://optimistic.etherscan.io/address/{address}",
|
|
245
243
|
},
|
operate/migration.py
CHANGED
|
@@ -22,9 +22,25 @@
|
|
|
22
22
|
|
|
23
23
|
import json
|
|
24
24
|
import logging
|
|
25
|
+
import shutil
|
|
26
|
+
import traceback
|
|
25
27
|
from pathlib import Path
|
|
28
|
+
from time import time
|
|
26
29
|
|
|
30
|
+
from aea_cli_ipfs.ipfs_utils import IPFSTool
|
|
31
|
+
|
|
32
|
+
from operate.constants import ZERO_ADDRESS
|
|
33
|
+
from operate.operate_types import Chain, LedgerType
|
|
34
|
+
from operate.services.manage import ServiceManager
|
|
35
|
+
from operate.services.service import (
|
|
36
|
+
DEFAULT_TRADER_ENV_VARS,
|
|
37
|
+
NON_EXISTENT_MULTISIG,
|
|
38
|
+
SERVICE_CONFIG_PREFIX,
|
|
39
|
+
SERVICE_CONFIG_VERSION,
|
|
40
|
+
Service,
|
|
41
|
+
)
|
|
27
42
|
from operate.utils import create_backup
|
|
43
|
+
from operate.wallet.master import LEDGER_TYPE_TO_WALLET_CLASS, MasterWalletManager
|
|
28
44
|
|
|
29
45
|
|
|
30
46
|
class MigrationManager:
|
|
@@ -42,6 +58,12 @@ class MigrationManager:
|
|
|
42
58
|
self._path = home
|
|
43
59
|
self.logger = logger
|
|
44
60
|
|
|
61
|
+
def log_directories(self, path: Path) -> None:
|
|
62
|
+
"""Log directories present in `path`."""
|
|
63
|
+
directories = [f" - {str(p)}" for p in path.iterdir() if p.is_dir()]
|
|
64
|
+
directories_str = "\n".join(directories)
|
|
65
|
+
self.logger.info(f"Directories in {path}\n: {directories_str}")
|
|
66
|
+
|
|
45
67
|
def migrate_user_account(self) -> None:
|
|
46
68
|
"""Migrates user.json"""
|
|
47
69
|
|
|
@@ -61,3 +83,307 @@ class MigrationManager:
|
|
|
61
83
|
json.dump(new_data, f, indent=4)
|
|
62
84
|
|
|
63
85
|
self.logger.info("[MIGRATION MANAGER] Migrated user.json.")
|
|
86
|
+
|
|
87
|
+
def migrate_wallets(self, wallet_manager: MasterWalletManager) -> None:
|
|
88
|
+
"""Migrate old wallet config formats to new ones, if applies."""
|
|
89
|
+
self.logger.info("Migrating wallet configs...")
|
|
90
|
+
|
|
91
|
+
for ledger_type in LedgerType:
|
|
92
|
+
if not wallet_manager.exists(ledger_type=ledger_type):
|
|
93
|
+
continue
|
|
94
|
+
|
|
95
|
+
wallet_class = LEDGER_TYPE_TO_WALLET_CLASS.get(ledger_type)
|
|
96
|
+
if wallet_class is None:
|
|
97
|
+
continue
|
|
98
|
+
|
|
99
|
+
migrated = wallet_class.migrate_format(path=wallet_manager.path)
|
|
100
|
+
if migrated:
|
|
101
|
+
self.logger.info(f"Wallet {wallet_class} has been migrated.")
|
|
102
|
+
|
|
103
|
+
self.logger.info("Migrating wallet configs done.")
|
|
104
|
+
|
|
105
|
+
@staticmethod
|
|
106
|
+
def _migrate_service( # pylint: disable=too-many-statements,too-many-locals
|
|
107
|
+
path: Path,
|
|
108
|
+
) -> bool:
|
|
109
|
+
"""Migrate the JSON file format if needed."""
|
|
110
|
+
|
|
111
|
+
if not path.is_dir():
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
if not path.name.startswith(SERVICE_CONFIG_PREFIX) and not path.name.startswith(
|
|
115
|
+
"bafybei"
|
|
116
|
+
):
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
if path.name.startswith("bafybei"):
|
|
120
|
+
backup_name = f"backup_{int(time())}_{path.name}"
|
|
121
|
+
backup_path = path.parent / backup_name
|
|
122
|
+
shutil.copytree(path, backup_path)
|
|
123
|
+
deployment_path = backup_path / "deployment"
|
|
124
|
+
if deployment_path.is_dir():
|
|
125
|
+
shutil.rmtree(deployment_path)
|
|
126
|
+
|
|
127
|
+
with open(
|
|
128
|
+
path / Service._file, # pylint: disable=protected-access
|
|
129
|
+
"r",
|
|
130
|
+
encoding="utf-8",
|
|
131
|
+
) as file:
|
|
132
|
+
data = json.load(file)
|
|
133
|
+
|
|
134
|
+
version = data.get("version", 0)
|
|
135
|
+
if version > SERVICE_CONFIG_VERSION:
|
|
136
|
+
raise RuntimeError(
|
|
137
|
+
f"Service configuration in {path} has version {version}, which means it was created with a newer version of olas-operate-middleware. Only configuration versions <= {SERVICE_CONFIG_VERSION} are supported by this version of olas-operate-middleware."
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Complete missing env vars for trader
|
|
141
|
+
if "trader" in data["name"].lower():
|
|
142
|
+
data.setdefault("env_variables", {})
|
|
143
|
+
|
|
144
|
+
for key, value in DEFAULT_TRADER_ENV_VARS.items():
|
|
145
|
+
if key not in data["env_variables"]:
|
|
146
|
+
data["env_variables"][key] = value
|
|
147
|
+
|
|
148
|
+
with open(
|
|
149
|
+
path / Service._file, # pylint: disable=protected-access
|
|
150
|
+
"w",
|
|
151
|
+
encoding="utf-8",
|
|
152
|
+
) as file:
|
|
153
|
+
json.dump(data, file, indent=2)
|
|
154
|
+
|
|
155
|
+
if version == SERVICE_CONFIG_VERSION:
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
# Migration steps for older versions
|
|
159
|
+
if version == 0:
|
|
160
|
+
new_data = {
|
|
161
|
+
"version": 2,
|
|
162
|
+
"hash": data.get("hash"),
|
|
163
|
+
"keys": data.get("keys"),
|
|
164
|
+
"home_chain_id": "100", # This is the default value for version 2 - do not change, will be corrected below
|
|
165
|
+
"chain_configs": {
|
|
166
|
+
"100": { # This is the default value for version 2 - do not change, will be corrected below
|
|
167
|
+
"ledger_config": {
|
|
168
|
+
"rpc": data.get("ledger_config", {}).get("rpc"),
|
|
169
|
+
"type": data.get("ledger_config", {}).get("type"),
|
|
170
|
+
"chain": data.get("ledger_config", {}).get("chain"),
|
|
171
|
+
},
|
|
172
|
+
"chain_data": {
|
|
173
|
+
"instances": data.get("chain_data", {}).get(
|
|
174
|
+
"instances", []
|
|
175
|
+
),
|
|
176
|
+
"token": data.get("chain_data", {}).get("token"),
|
|
177
|
+
"multisig": data.get("chain_data", {}).get("multisig"),
|
|
178
|
+
"staked": data.get("chain_data", {}).get("staked", False),
|
|
179
|
+
"on_chain_state": data.get("chain_data", {}).get(
|
|
180
|
+
"on_chain_state", 3
|
|
181
|
+
),
|
|
182
|
+
"user_params": {
|
|
183
|
+
"staking_program_id": "pearl_alpha",
|
|
184
|
+
"nft": data.get("chain_data", {})
|
|
185
|
+
.get("user_params", {})
|
|
186
|
+
.get("nft"),
|
|
187
|
+
"threshold": data.get("chain_data", {})
|
|
188
|
+
.get("user_params", {})
|
|
189
|
+
.get("threshold"),
|
|
190
|
+
"use_staking": data.get("chain_data", {})
|
|
191
|
+
.get("user_params", {})
|
|
192
|
+
.get("use_staking"),
|
|
193
|
+
"cost_of_bond": data.get("chain_data", {})
|
|
194
|
+
.get("user_params", {})
|
|
195
|
+
.get("cost_of_bond"),
|
|
196
|
+
"fund_requirements": data.get("chain_data", {})
|
|
197
|
+
.get("user_params", {})
|
|
198
|
+
.get("fund_requirements", {}),
|
|
199
|
+
"agent_id": data.get("chain_data", {})
|
|
200
|
+
.get("user_params", {})
|
|
201
|
+
.get("agent_id", "14"),
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
"service_path": data.get("service_path", ""),
|
|
207
|
+
"name": data.get("name", ""),
|
|
208
|
+
}
|
|
209
|
+
data = new_data
|
|
210
|
+
|
|
211
|
+
if version < 4:
|
|
212
|
+
# Add missing fields introduced in later versions, if necessary.
|
|
213
|
+
for _, chain_data in data.get("chain_configs", {}).items():
|
|
214
|
+
chain_data.setdefault("chain_data", {}).setdefault(
|
|
215
|
+
"user_params", {}
|
|
216
|
+
).setdefault("use_mech_marketplace", False)
|
|
217
|
+
service_name = data.get("name", "")
|
|
218
|
+
agent_id = Service.determine_agent_id(service_name)
|
|
219
|
+
chain_data.setdefault("chain_data", {}).setdefault("user_params", {})[
|
|
220
|
+
"agent_id"
|
|
221
|
+
] = agent_id
|
|
222
|
+
|
|
223
|
+
data["description"] = data.setdefault("description", data.get("name"))
|
|
224
|
+
data["hash_history"] = data.setdefault(
|
|
225
|
+
"hash_history", {int(time()): data["hash"]}
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
if "service_config_id" not in data:
|
|
229
|
+
service_config_id = Service.get_new_service_config_id(path)
|
|
230
|
+
new_path = path.parent / service_config_id
|
|
231
|
+
data["service_config_id"] = service_config_id
|
|
232
|
+
path = path.rename(new_path)
|
|
233
|
+
|
|
234
|
+
old_to_new_ledgers = ["ethereum", "solana"]
|
|
235
|
+
for key_data in data["keys"]:
|
|
236
|
+
key_data["ledger"] = old_to_new_ledgers[key_data["ledger"]]
|
|
237
|
+
|
|
238
|
+
old_to_new_chains = [
|
|
239
|
+
"ethereum",
|
|
240
|
+
"goerli",
|
|
241
|
+
"gnosis",
|
|
242
|
+
"solana",
|
|
243
|
+
"optimism",
|
|
244
|
+
"base",
|
|
245
|
+
"mode",
|
|
246
|
+
]
|
|
247
|
+
new_chain_configs = {}
|
|
248
|
+
for chain_id, chain_data in data["chain_configs"].items():
|
|
249
|
+
chain_data["ledger_config"]["chain"] = old_to_new_chains[
|
|
250
|
+
chain_data["ledger_config"]["chain"]
|
|
251
|
+
]
|
|
252
|
+
del chain_data["ledger_config"]["type"]
|
|
253
|
+
new_chain_configs[Chain.from_id(int(chain_id)).value] = chain_data # type: ignore
|
|
254
|
+
|
|
255
|
+
data["chain_configs"] = new_chain_configs
|
|
256
|
+
data["home_chain"] = data.setdefault("home_chain", Chain.from_id(int(data.get("home_chain_id", "100"))).value) # type: ignore
|
|
257
|
+
del data["home_chain_id"]
|
|
258
|
+
|
|
259
|
+
if "env_variables" not in data:
|
|
260
|
+
if data["name"] == "valory/trader_pearl":
|
|
261
|
+
data["env_variables"] = DEFAULT_TRADER_ENV_VARS
|
|
262
|
+
else:
|
|
263
|
+
data["env_variables"] = {}
|
|
264
|
+
|
|
265
|
+
if version < 5:
|
|
266
|
+
new_chain_configs = {}
|
|
267
|
+
for chain, chain_data in data["chain_configs"].items():
|
|
268
|
+
fund_requirements = chain_data["chain_data"]["user_params"][
|
|
269
|
+
"fund_requirements"
|
|
270
|
+
]
|
|
271
|
+
if ZERO_ADDRESS not in fund_requirements:
|
|
272
|
+
chain_data["chain_data"]["user_params"]["fund_requirements"] = {
|
|
273
|
+
ZERO_ADDRESS: fund_requirements
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
new_chain_configs[chain] = chain_data # type: ignore
|
|
277
|
+
data["chain_configs"] = new_chain_configs
|
|
278
|
+
|
|
279
|
+
if version < 7:
|
|
280
|
+
for _, chain_data in data.get("chain_configs", {}).items():
|
|
281
|
+
if chain_data["chain_data"]["multisig"] == "0xm":
|
|
282
|
+
chain_data["chain_data"]["multisig"] = NON_EXISTENT_MULTISIG
|
|
283
|
+
|
|
284
|
+
data["agent_addresses"] = [key["address"] for key in data["keys"]]
|
|
285
|
+
del data["keys"]
|
|
286
|
+
|
|
287
|
+
if version < 8:
|
|
288
|
+
if data["home_chain"] == "optimistic":
|
|
289
|
+
data["home_chain"] = Chain.OPTIMISM.value
|
|
290
|
+
|
|
291
|
+
if "optimistic" in data["chain_configs"]:
|
|
292
|
+
data["chain_configs"]["optimism"] = data["chain_configs"].pop(
|
|
293
|
+
"optimistic"
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
for _, chain_config in data["chain_configs"].items():
|
|
297
|
+
if chain_config["ledger_config"]["chain"] == "optimistic":
|
|
298
|
+
chain_config["ledger_config"]["chain"] = Chain.OPTIMISM.value
|
|
299
|
+
|
|
300
|
+
data["version"] = SERVICE_CONFIG_VERSION
|
|
301
|
+
|
|
302
|
+
# Redownload service path
|
|
303
|
+
if "service_path" in data:
|
|
304
|
+
package_absolute_path = path / Path(data["service_path"]).name
|
|
305
|
+
data.pop("service_path")
|
|
306
|
+
else:
|
|
307
|
+
package_absolute_path = path / data["package_path"]
|
|
308
|
+
|
|
309
|
+
if package_absolute_path.exists() and package_absolute_path.is_dir():
|
|
310
|
+
shutil.rmtree(package_absolute_path)
|
|
311
|
+
|
|
312
|
+
package_absolute_path = Path(
|
|
313
|
+
IPFSTool().download(
|
|
314
|
+
hash_id=data["hash"],
|
|
315
|
+
target_dir=path,
|
|
316
|
+
)
|
|
317
|
+
)
|
|
318
|
+
data["package_path"] = str(package_absolute_path.name)
|
|
319
|
+
|
|
320
|
+
with open(
|
|
321
|
+
path / Service._file, # pylint: disable=protected-access
|
|
322
|
+
"w",
|
|
323
|
+
encoding="utf-8",
|
|
324
|
+
) as file:
|
|
325
|
+
json.dump(data, file, indent=2)
|
|
326
|
+
|
|
327
|
+
return True
|
|
328
|
+
|
|
329
|
+
def migrate_services(self, service_manager: ServiceManager) -> None:
|
|
330
|
+
"""Migrate old service config formats to new ones, if applies."""
|
|
331
|
+
self.log_directories(service_manager.path)
|
|
332
|
+
self.logger.info("Migrating service configs...")
|
|
333
|
+
|
|
334
|
+
bafybei_count = sum(
|
|
335
|
+
1
|
|
336
|
+
for path in service_manager.path.iterdir()
|
|
337
|
+
if path.name.startswith("bafybei")
|
|
338
|
+
)
|
|
339
|
+
if bafybei_count > 1:
|
|
340
|
+
raise RuntimeError(
|
|
341
|
+
f"Your services folder contains {bafybei_count} folders starting with 'bafybei'. This is an unintended situation. Please contact support."
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
paths = list(service_manager.path.iterdir())
|
|
345
|
+
for path in paths:
|
|
346
|
+
try:
|
|
347
|
+
if path.name.startswith(SERVICE_CONFIG_PREFIX) or path.name.startswith(
|
|
348
|
+
"bafybei"
|
|
349
|
+
):
|
|
350
|
+
self.logger.info(f"migrate_service_configs {str(path)}")
|
|
351
|
+
migrated = self._migrate_service(path)
|
|
352
|
+
if migrated:
|
|
353
|
+
self.logger.info(f"Folder {str(path)} has been migrated.")
|
|
354
|
+
except Exception as e: # pylint: disable=broad-except
|
|
355
|
+
self.logger.error(
|
|
356
|
+
f"Failed to migrate service: {path.name}. Exception {e}: {traceback.format_exc()}"
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
self.logger.info("Migrating service configs done.")
|
|
360
|
+
self.log_directories(service_manager.path)
|
|
361
|
+
|
|
362
|
+
def migrate_qs_configs(self) -> None:
|
|
363
|
+
"""Migrates quickstart configs."""
|
|
364
|
+
|
|
365
|
+
for qs_config in self._path.glob("*-quickstart-config.json"):
|
|
366
|
+
if not qs_config.exists():
|
|
367
|
+
continue
|
|
368
|
+
|
|
369
|
+
migrated = False
|
|
370
|
+
with open(qs_config, "r", encoding="utf-8") as f:
|
|
371
|
+
data = json.load(f)
|
|
372
|
+
|
|
373
|
+
if "optimistic" in data.get("rpc", {}):
|
|
374
|
+
data["rpc"]["optimism"] = data["rpc"].pop("optimistic")
|
|
375
|
+
migrated = True
|
|
376
|
+
|
|
377
|
+
if "optimistic" == data.get("principal_chain", ""):
|
|
378
|
+
data["principal_chain"] = "optimism"
|
|
379
|
+
migrated = True
|
|
380
|
+
|
|
381
|
+
if not migrated:
|
|
382
|
+
continue
|
|
383
|
+
|
|
384
|
+
with open(qs_config, "w", encoding="utf-8") as f:
|
|
385
|
+
json.dump(data, f, indent=2)
|
|
386
|
+
|
|
387
|
+
self.logger.info(
|
|
388
|
+
"[MIGRATION MANAGER] Migrated quickstart config: %s.", qs_config.name
|
|
389
|
+
)
|
operate/operate_types.py
CHANGED
|
@@ -28,16 +28,10 @@ from autonomy.chain.config import ChainType
|
|
|
28
28
|
from autonomy.chain.constants import CHAIN_NAME_TO_CHAIN_ID
|
|
29
29
|
from typing_extensions import TypedDict
|
|
30
30
|
|
|
31
|
+
from operate.constants import NO_STAKING_PROGRAM_ID
|
|
31
32
|
from operate.resource import LocalResource
|
|
32
33
|
|
|
33
34
|
|
|
34
|
-
_ACTIONS = {
|
|
35
|
-
"status": 0,
|
|
36
|
-
"build": 1,
|
|
37
|
-
"deploy": 2,
|
|
38
|
-
"stop": 3,
|
|
39
|
-
}
|
|
40
|
-
|
|
41
35
|
CHAIN_NAME_TO_CHAIN_ID["solana"] = 900
|
|
42
36
|
|
|
43
37
|
_CHAIN_ID_TO_CHAIN_NAME = {
|
|
@@ -127,20 +121,6 @@ for name in dir(ChainMixin):
|
|
|
127
121
|
setattr(Chain, name, getattr(ChainMixin, name))
|
|
128
122
|
|
|
129
123
|
|
|
130
|
-
class Action(enum.IntEnum):
|
|
131
|
-
"""Action payload."""
|
|
132
|
-
|
|
133
|
-
STATUS = 0
|
|
134
|
-
BUILD = 1
|
|
135
|
-
DEPLOY = 2
|
|
136
|
-
STOP = 3
|
|
137
|
-
|
|
138
|
-
@classmethod
|
|
139
|
-
def from_string(cls, action: str) -> "Action":
|
|
140
|
-
"""Load from string."""
|
|
141
|
-
return cls(_ACTIONS[action])
|
|
142
|
-
|
|
143
|
-
|
|
144
124
|
class DeploymentStatus(enum.IntEnum):
|
|
145
125
|
"""Status payload."""
|
|
146
126
|
|
|
@@ -208,9 +188,6 @@ class ConfigurationTemplate(TypedDict):
|
|
|
208
188
|
nft: str
|
|
209
189
|
rpc: str
|
|
210
190
|
agent_id: int
|
|
211
|
-
threshold: int
|
|
212
|
-
use_staking: bool
|
|
213
|
-
use_mech_marketplace: bool
|
|
214
191
|
cost_of_bond: int
|
|
215
192
|
fund_requirements: t.Dict[str, FundRequirementsTemplate]
|
|
216
193
|
fallback_chain_params: t.Optional[t.Dict]
|
|
@@ -275,13 +252,18 @@ class OnChainUserParams(LocalResource):
|
|
|
275
252
|
|
|
276
253
|
staking_program_id: str
|
|
277
254
|
nft: str
|
|
278
|
-
threshold: int
|
|
279
255
|
agent_id: int
|
|
280
|
-
use_staking: bool
|
|
281
|
-
use_mech_marketplace: bool
|
|
282
256
|
cost_of_bond: int
|
|
283
257
|
fund_requirements: OnChainTokenRequirements
|
|
284
258
|
|
|
259
|
+
@property
|
|
260
|
+
def use_staking(self) -> bool:
|
|
261
|
+
"""Check if staking is used."""
|
|
262
|
+
return (
|
|
263
|
+
self.staking_program_id is not None
|
|
264
|
+
and self.staking_program_id != NO_STAKING_PROGRAM_ID
|
|
265
|
+
)
|
|
266
|
+
|
|
285
267
|
@classmethod
|
|
286
268
|
def from_json(cls, obj: t.Dict) -> "OnChainUserParams":
|
|
287
269
|
"""Load a service"""
|
|
@@ -25,7 +25,7 @@ import sys
|
|
|
25
25
|
from pathlib import Path
|
|
26
26
|
from typing import List, TYPE_CHECKING, Union
|
|
27
27
|
|
|
28
|
-
from operate.constants import
|
|
28
|
+
from operate.constants import DEPLOYMENT_DIR
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
if TYPE_CHECKING:
|
|
@@ -38,10 +38,10 @@ def find_build_directory(config_file: Path, operate: "OperateApp") -> Path:
|
|
|
38
38
|
config = json.load(f)
|
|
39
39
|
config_service_hash = config.get("hash")
|
|
40
40
|
|
|
41
|
-
services = operate.service_manager().
|
|
41
|
+
services = operate.service_manager().get_all_services()
|
|
42
42
|
for service in services:
|
|
43
43
|
if service.hash == config_service_hash:
|
|
44
|
-
build_dir = service.path /
|
|
44
|
+
build_dir = service.path / DEPLOYMENT_DIR
|
|
45
45
|
if not build_dir.exists():
|
|
46
46
|
print(f"{config.get('name')} not deployed.")
|
|
47
47
|
sys.exit(1)
|
|
@@ -107,9 +107,6 @@ def analyse_logs(
|
|
|
107
107
|
print(f"Config file '{config_file}' not found.")
|
|
108
108
|
sys.exit(1)
|
|
109
109
|
|
|
110
|
-
operate.service_manager().migrate_service_configs()
|
|
111
|
-
operate.wallet_manager.migrate_wallet_configs()
|
|
112
|
-
|
|
113
110
|
# Auto-detect the logs directory
|
|
114
111
|
build_dir = find_build_directory(config_file, operate)
|
|
115
112
|
logs_dir = build_dir / "persistent_data" / "logs"
|
|
@@ -48,9 +48,6 @@ def claim_staking_rewards(operate: "OperateApp", config_path: str) -> None:
|
|
|
48
48
|
|
|
49
49
|
print_section(f"Claim staking rewards for {template['name']}")
|
|
50
50
|
|
|
51
|
-
operate.service_manager().migrate_service_configs()
|
|
52
|
-
operate.wallet_manager.migrate_wallet_configs()
|
|
53
|
-
|
|
54
51
|
# check if agent was started before
|
|
55
52
|
config = load_local_config(
|
|
56
53
|
operate=operate, service_name=cast(str, template["name"])
|
|
@@ -70,10 +67,10 @@ def claim_staking_rewards(operate: "OperateApp", config_path: str) -> None:
|
|
|
70
67
|
|
|
71
68
|
print("")
|
|
72
69
|
|
|
70
|
+
ask_password_if_needed(operate)
|
|
73
71
|
config = configure_local_config(template, operate)
|
|
74
72
|
manager = operate.service_manager()
|
|
75
73
|
service = get_service(manager, template)
|
|
76
|
-
ask_password_if_needed(operate)
|
|
77
74
|
|
|
78
75
|
# reload manger and config after setting operate.password
|
|
79
76
|
manager = operate.service_manager()
|
|
@@ -70,9 +70,6 @@ def reset_configs(operate: "OperateApp", config_path: str) -> None:
|
|
|
70
70
|
with open(config_path, "r") as config_file:
|
|
71
71
|
template = json.load(config_file)
|
|
72
72
|
|
|
73
|
-
operate.service_manager().migrate_service_configs()
|
|
74
|
-
operate.wallet_manager.migrate_wallet_configs()
|
|
75
|
-
|
|
76
73
|
print_title(f"Reset your {template['name']} configurations")
|
|
77
74
|
|
|
78
75
|
# check if agent was started before
|
|
@@ -35,9 +35,6 @@ def reset_password(operate: "OperateApp") -> None:
|
|
|
35
35
|
"""Reset password."""
|
|
36
36
|
print_title("Reset your password")
|
|
37
37
|
|
|
38
|
-
operate.service_manager().migrate_service_configs()
|
|
39
|
-
operate.wallet_manager.migrate_wallet_configs()
|
|
40
|
-
|
|
41
38
|
# check if agent was started before
|
|
42
39
|
if not (operate._path / "user.json").exists():
|
|
43
40
|
print("No previous agent setup found. Exiting.")
|
|
@@ -22,7 +22,8 @@ import json
|
|
|
22
22
|
import os
|
|
23
23
|
from typing import TYPE_CHECKING, cast
|
|
24
24
|
|
|
25
|
-
from operate.
|
|
25
|
+
from operate.constants import NO_STAKING_PROGRAM_ID
|
|
26
|
+
from operate.ledger.profiles import get_staking_contract
|
|
26
27
|
from operate.quickstart.run_service import (
|
|
27
28
|
CUSTOM_PROGRAM_ID,
|
|
28
29
|
ask_password_if_needed,
|
|
@@ -44,9 +45,6 @@ def reset_staking(operate: "OperateApp", config_path: str) -> None:
|
|
|
44
45
|
with open(config_path, "r") as config_file:
|
|
45
46
|
template = json.load(config_file)
|
|
46
47
|
|
|
47
|
-
operate.service_manager().migrate_service_configs()
|
|
48
|
-
operate.wallet_manager.migrate_wallet_configs()
|
|
49
|
-
|
|
50
48
|
print_title("Reset your staking program preference")
|
|
51
49
|
|
|
52
50
|
# check if agent was started before
|
|
@@ -57,6 +55,7 @@ def reset_staking(operate: "OperateApp", config_path: str) -> None:
|
|
|
57
55
|
print("No previous agent setup found. Exiting.")
|
|
58
56
|
return
|
|
59
57
|
|
|
58
|
+
ask_password_if_needed(operate)
|
|
60
59
|
config = configure_local_config(template, operate)
|
|
61
60
|
assert ( # nosec
|
|
62
61
|
config.principal_chain is not None
|
|
@@ -82,7 +81,6 @@ def reset_staking(operate: "OperateApp", config_path: str) -> None:
|
|
|
82
81
|
print("Cancelled.")
|
|
83
82
|
return
|
|
84
83
|
|
|
85
|
-
ask_password_if_needed(operate)
|
|
86
84
|
manager = operate.service_manager()
|
|
87
85
|
service = get_service(manager, template)
|
|
88
86
|
|