olas-operate-middleware 0.7.0__py3-none-any.whl → 0.8.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.7.0.dist-info → olas_operate_middleware-0.8.0.dist-info}/METADATA +1 -1
- {olas_operate_middleware-0.7.0.dist-info → olas_operate_middleware-0.8.0.dist-info}/RECORD +16 -16
- operate/bridge/providers/relay_provider.py +1 -1
- operate/cli.py +114 -105
- operate/ledger/profiles.py +9 -35
- operate/operate_types.py +10 -0
- operate/quickstart/claim_staking_rewards.py +1 -1
- operate/quickstart/reset_staking.py +1 -1
- operate/quickstart/run_service.py +19 -26
- operate/quickstart/terminate_on_chain_service.py +1 -1
- operate/quickstart/utils.py +0 -1
- operate/services/agent_runner.py +1 -1
- operate/services/manage.py +126 -99
- {olas_operate_middleware-0.7.0.dist-info → olas_operate_middleware-0.8.0.dist-info}/LICENSE +0 -0
- {olas_operate_middleware-0.7.0.dist-info → olas_operate_middleware-0.8.0.dist-info}/WHEEL +0 -0
- {olas_operate_middleware-0.7.0.dist-info → olas_operate_middleware-0.8.0.dist-info}/entry_points.txt +0 -0
|
@@ -5,8 +5,8 @@ operate/bridge/bridge_manager.py,sha256=ZLUqrjB78F8skaGTz43WDzM3i7UQod60b19OCczl
|
|
|
5
5
|
operate/bridge/providers/lifi_provider.py,sha256=FpAlBAA_gOt-oOHKhGaOQhhTZIL-hgYYo4IIw1FN7mo,14153
|
|
6
6
|
operate/bridge/providers/native_bridge_provider.py,sha256=ZTLBdh9ttPWpX8IYvHyVU5y3pg1B1DG_vQ9DHVquDfw,24666
|
|
7
7
|
operate/bridge/providers/provider.py,sha256=U-mgf02lS9g4tGgmDJZ4GQKX9kbf4bPQY-oNWsp3kUk,19813
|
|
8
|
-
operate/bridge/providers/relay_provider.py,sha256=
|
|
9
|
-
operate/cli.py,sha256=
|
|
8
|
+
operate/bridge/providers/relay_provider.py,sha256=krwui645N-Q0xmc3goDSUxJSpJYfxX18st_GQGKlF_A,16750
|
|
9
|
+
operate/cli.py,sha256=lhX4eViV1lKx6jlLr7pmbGiNLeq2pkqlYXupZRRh9X0,47862
|
|
10
10
|
operate/constants.py,sha256=oFkCw3p3fPA4MDft61e_tSIxNhpqWBauUpQF3ZSn9QI,2662
|
|
11
11
|
operate/data/README.md,sha256=jGPyZTvg2LCGdllvmYxmFMkkkiXb6YWatbqIkcX3kv4,879
|
|
12
12
|
operate/data/__init__.py,sha256=ttC51Yqk9c4ehpIgs1Qbe7aJvzkrbbdZ1ClaCxJYByE,864
|
|
@@ -55,27 +55,27 @@ operate/data/contracts/uniswap_v2_erc20/tests/__init__.py,sha256=3Arw8dsCsJz6hVO
|
|
|
55
55
|
operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py,sha256=FzZbw9OTcr_yvjOXpk9YcO-K40eyDARyybcfSHDg2Ps,13392
|
|
56
56
|
operate/keys.py,sha256=soJfdXJvHo8ytWH6ShIndjUpkShPg3KzirLs7MoFe8I,3764
|
|
57
57
|
operate/ledger/__init__.py,sha256=kC-SYcdOQcX-v4TIWpwkSdM8L0yimEmbaL33XNY4S7Q,3361
|
|
58
|
-
operate/ledger/profiles.py,sha256=
|
|
58
|
+
operate/ledger/profiles.py,sha256=9o_04W6rjv3Dr73PUuDOfhFM1Sn4JrmHjEBwhVdHepE,12374
|
|
59
59
|
operate/migration.py,sha256=asWzYYSLhp0QmWov1eyEb9iGjzwZNOPDed01Z3Jnnn8,1819
|
|
60
60
|
operate/operate_http/__init__.py,sha256=dxCIVSUos23M4R-PFZZG6k5QrOlEiK0SxhCYSFNxh7U,4711
|
|
61
61
|
operate/operate_http/exceptions.py,sha256=4UFzrn-GyDD71RhkaOyFPBynL6TrrtP3eywaaU3o4fc,1339
|
|
62
|
-
operate/operate_types.py,sha256=
|
|
62
|
+
operate/operate_types.py,sha256=Ff6rpJIgoJ-wludFtW7nufAVkUyZ3_1TShCcn2KS8GQ,8228
|
|
63
63
|
operate/pearl.py,sha256=yrTpSXLu_ML3qT-uNxq3kScOyo31JyxBujiSMfMUbcg,1690
|
|
64
64
|
operate/quickstart/analyse_logs.py,sha256=18y0JRGEryLILM_Aj2nINyMlUodA42DaypjWLev1ENs,4297
|
|
65
|
-
operate/quickstart/claim_staking_rewards.py,sha256
|
|
65
|
+
operate/quickstart/claim_staking_rewards.py,sha256=VVRhYQmWJ9xWigWA6vABugIllzC1VCoehnA_Wpg4DG4,4135
|
|
66
66
|
operate/quickstart/reset_configs.py,sha256=t-gVt0_-Th-LADfVmjxxKXjE2if5w-MuEscGFyMw2u0,3450
|
|
67
67
|
operate/quickstart/reset_password.py,sha256=_HHnwX032WKNja5koegQIy4By0rFXGcdQRgVlusf5GA,2644
|
|
68
|
-
operate/quickstart/reset_staking.py,sha256=
|
|
69
|
-
operate/quickstart/run_service.py,sha256=
|
|
68
|
+
operate/quickstart/reset_staking.py,sha256=f1_cM7QJWrCySpGJyHaDvpHbd_we39fHzBAlGLfHB_M,5157
|
|
69
|
+
operate/quickstart/run_service.py,sha256=b2194M2TRi5Me4gZnC-TpWpajeh5eAgkNGwKpHpOK1A,27292
|
|
70
70
|
operate/quickstart/stop_service.py,sha256=ENuFBd3KaTs0NFTy-6ECrp5XI8MRJcIOUevWF82WSt4,2094
|
|
71
|
-
operate/quickstart/terminate_on_chain_service.py,sha256=
|
|
72
|
-
operate/quickstart/utils.py,sha256=
|
|
71
|
+
operate/quickstart/terminate_on_chain_service.py,sha256=ZsUSZp-xiAaUipU3nXqZzIiu-KIX_x0r2baFdgFTeQE,3023
|
|
72
|
+
operate/quickstart/utils.py,sha256=rv70bktB31q6uw5hNkT6u5yo0kdpG5DCQQrQ7000W80,9172
|
|
73
73
|
operate/resource.py,sha256=iuLlUepc18XTk1rEeC3Skt1R0v6cHST9rQxR6h4Ldg0,5179
|
|
74
74
|
operate/services/__init__.py,sha256=isrThS-Ccu5Sc15JZgkN4uTAVaSg-NwUUSDeTyJEqLk,855
|
|
75
|
-
operate/services/agent_runner.py,sha256=
|
|
75
|
+
operate/services/agent_runner.py,sha256=6tJePUJmlRxlIugT2fDaCJHSrQlDnl1t9pbg3-7EmCQ,7560
|
|
76
76
|
operate/services/deployment_runner.py,sha256=eP1bnT3PdkYtPxi-4sZ6-Wopz8u88NkeZx7vOB2vkzc,22217
|
|
77
77
|
operate/services/health_checker.py,sha256=pXtzFTLv4PK1OSbDCZ_RnOnvX31mPYRR16tbC7BsUNw,9754
|
|
78
|
-
operate/services/manage.py,sha256=
|
|
78
|
+
operate/services/manage.py,sha256=oDp4kMBAynPYqe3b2LM4kR9xefNxPVmmvO50XwTxFZQ,110310
|
|
79
79
|
operate/services/protocol.py,sha256=0LcZk-zzQ2hYzZAkn_KIQGgT32Bq3_UsbBl7Ert3Ho8,60157
|
|
80
80
|
operate/services/service.py,sha256=2fQeRbjc4PBzRQ4jD9peKjAwBMKABS_hNoe-BrRutPc,47250
|
|
81
81
|
operate/services/utils/__init__.py,sha256=TvioaZ1mfTRUSCtrQoLNAp4WMVXyqEJqFJM4PxSQCRU,24
|
|
@@ -85,8 +85,8 @@ operate/utils/__init__.py,sha256=cFNP2XFpjJmDLskN0SzAk5FPdqaeN2Jn4MyVbFHmH2M,307
|
|
|
85
85
|
operate/utils/gnosis.py,sha256=Z1IgGfQgKIrI7EyBpGFbJ2RFaeD4Fk_7D4P-_ZQfH6Q,17705
|
|
86
86
|
operate/wallet/__init__.py,sha256=NGiozD3XhvkBi7_FaOWQ8x1thZPK4uGpokJaeDY_o2w,813
|
|
87
87
|
operate/wallet/master.py,sha256=FQrchjWhJKgif3IXztxS0SHm7aVaAJYFQ-FEXQgxQes,31021
|
|
88
|
-
olas_operate_middleware-0.
|
|
89
|
-
olas_operate_middleware-0.
|
|
90
|
-
olas_operate_middleware-0.
|
|
91
|
-
olas_operate_middleware-0.
|
|
92
|
-
olas_operate_middleware-0.
|
|
88
|
+
olas_operate_middleware-0.8.0.dist-info/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
|
|
89
|
+
olas_operate_middleware-0.8.0.dist-info/METADATA,sha256=8L8vv-OR6f3STUGttsNhvOr9Gb-C4-vZ4mhm5E18p2A,2034
|
|
90
|
+
olas_operate_middleware-0.8.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
91
|
+
olas_operate_middleware-0.8.0.dist-info/entry_points.txt,sha256=dM1g2I7ODApKQFcgl5J4NGA7pfBTo6qsUTXM-j2OLlw,44
|
|
92
|
+
olas_operate_middleware-0.8.0.dist-info/RECORD,,
|
|
@@ -173,7 +173,7 @@ class RelayProvider(Provider):
|
|
|
173
173
|
"destinationChainId": Chain(to_chain).id,
|
|
174
174
|
"recipient": to_address,
|
|
175
175
|
"destinationCurrency": to_token,
|
|
176
|
-
"amount": to_amount,
|
|
176
|
+
"amount": str(to_amount),
|
|
177
177
|
"tradeType": "EXACT_OUTPUT",
|
|
178
178
|
"enableTrueExactOutput": False,
|
|
179
179
|
}
|
operate/cli.py
CHANGED
|
@@ -75,12 +75,13 @@ from operate.utils.gnosis import get_assets_balances
|
|
|
75
75
|
from operate.wallet.master import MasterWalletManager
|
|
76
76
|
|
|
77
77
|
|
|
78
|
-
DEFAULT_HARDHAT_KEY = (
|
|
79
|
-
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
|
|
80
|
-
).encode()
|
|
81
78
|
DEFAULT_MAX_RETRIES = 3
|
|
82
79
|
USER_NOT_LOGGED_IN_ERROR = JSONResponse(
|
|
83
|
-
content={"error": "User not logged in
|
|
80
|
+
content={"error": "User not logged in."}, status_code=HTTPStatus.UNAUTHORIZED
|
|
81
|
+
)
|
|
82
|
+
ACCOUNT_NOT_FOUND_ERROR = JSONResponse(
|
|
83
|
+
content={"error": "User account not found."},
|
|
84
|
+
status_code=HTTPStatus.NOT_FOUND,
|
|
84
85
|
)
|
|
85
86
|
|
|
86
87
|
|
|
@@ -130,7 +131,7 @@ class OperateApp:
|
|
|
130
131
|
"""Updates current password"""
|
|
131
132
|
|
|
132
133
|
if not new_password:
|
|
133
|
-
raise ValueError("
|
|
134
|
+
raise ValueError("'password' is required.")
|
|
134
135
|
|
|
135
136
|
if not (
|
|
136
137
|
self.user_account.is_valid(old_password)
|
|
@@ -147,7 +148,7 @@ class OperateApp:
|
|
|
147
148
|
"""Updates current password using the mnemonic"""
|
|
148
149
|
|
|
149
150
|
if not new_password:
|
|
150
|
-
raise ValueError("
|
|
151
|
+
raise ValueError("'password' is required.")
|
|
151
152
|
|
|
152
153
|
mnemonic = mnemonic.strip().lower()
|
|
153
154
|
if not self.wallet_manager.is_mnemonic_valid(mnemonic):
|
|
@@ -352,30 +353,27 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
352
353
|
"""Call the endpoint."""
|
|
353
354
|
logger.info(f"Calling `{f.__name__}` with retries enabled")
|
|
354
355
|
retries = 0
|
|
355
|
-
errors = []
|
|
356
356
|
while retries < DEFAULT_MAX_RETRIES:
|
|
357
357
|
try:
|
|
358
358
|
return await f(request)
|
|
359
359
|
except (APIError, ProjectError) as e:
|
|
360
360
|
logger.error(f"Error {e}\n{traceback.format_exc()}")
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
error["error"] = "Service is already running"
|
|
361
|
+
if "has active endpoints" in str(e):
|
|
362
|
+
error_msg = "Service is already running."
|
|
364
363
|
else:
|
|
365
|
-
|
|
366
|
-
errors.append(error)
|
|
364
|
+
error_msg = "Service deployment failed. Please check the logs."
|
|
367
365
|
return JSONResponse(
|
|
368
|
-
content={"
|
|
366
|
+
content={"error": error_msg},
|
|
369
367
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
370
368
|
)
|
|
371
369
|
except Exception as e: # pylint: disable=broad-except
|
|
372
|
-
|
|
373
|
-
{"error": str(e.args[0]), "traceback": traceback.format_exc()}
|
|
374
|
-
)
|
|
375
|
-
logger.error(f"Error {str(e.args[0])}\n{traceback.format_exc()}")
|
|
370
|
+
logger.error(f"Error {str(e)}\n{traceback.format_exc()}")
|
|
376
371
|
retries += 1
|
|
377
372
|
return JSONResponse(
|
|
378
|
-
content={
|
|
373
|
+
content={
|
|
374
|
+
"error": "Operation failed after multiple attempts. Please try again later."
|
|
375
|
+
},
|
|
376
|
+
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
379
377
|
)
|
|
380
378
|
|
|
381
379
|
return _call
|
|
@@ -413,7 +411,7 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
413
411
|
"""Setup account."""
|
|
414
412
|
if operate.user_account is not None:
|
|
415
413
|
return JSONResponse(
|
|
416
|
-
content={"error": "Account already exists"},
|
|
414
|
+
content={"error": "Account already exists."},
|
|
417
415
|
status_code=HTTPStatus.CONFLICT,
|
|
418
416
|
)
|
|
419
417
|
|
|
@@ -436,10 +434,7 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
436
434
|
) -> t.Dict:
|
|
437
435
|
"""Update password."""
|
|
438
436
|
if operate.user_account is None:
|
|
439
|
-
return
|
|
440
|
-
content={"error": "Account does not exist."},
|
|
441
|
-
status_code=HTTPStatus.CONFLICT,
|
|
442
|
-
)
|
|
437
|
+
return ACCOUNT_NOT_FOUND_ERROR
|
|
443
438
|
|
|
444
439
|
data = await request.json()
|
|
445
440
|
old_password = data.get("old_password")
|
|
@@ -449,7 +444,7 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
449
444
|
if not old_password and not mnemonic:
|
|
450
445
|
return JSONResponse(
|
|
451
446
|
content={
|
|
452
|
-
"error": "
|
|
447
|
+
"error": "Exactly one of 'old_password' or 'mnemonic' (seed phrase) is required.",
|
|
453
448
|
},
|
|
454
449
|
status_code=HTTPStatus.BAD_REQUEST,
|
|
455
450
|
)
|
|
@@ -457,7 +452,7 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
457
452
|
if old_password and mnemonic:
|
|
458
453
|
return JSONResponse(
|
|
459
454
|
content={
|
|
460
|
-
"error": "
|
|
455
|
+
"error": "Exactly one of 'old_password' or 'mnemonic' (seed phrase) is required.",
|
|
461
456
|
},
|
|
462
457
|
status_code=HTTPStatus.BAD_REQUEST,
|
|
463
458
|
)
|
|
@@ -465,7 +460,7 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
465
460
|
if not new_password or len(new_password) < MIN_PASSWORD_LENGTH:
|
|
466
461
|
return JSONResponse(
|
|
467
462
|
content={
|
|
468
|
-
"error": f"
|
|
463
|
+
"error": f"New password must be at least {MIN_PASSWORD_LENGTH} characters long."
|
|
469
464
|
},
|
|
470
465
|
status_code=HTTPStatus.BAD_REQUEST,
|
|
471
466
|
)
|
|
@@ -474,27 +469,31 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
474
469
|
if old_password:
|
|
475
470
|
operate.update_password(old_password, new_password)
|
|
476
471
|
return JSONResponse(
|
|
477
|
-
content={"error": None, "message": "Password updated."}
|
|
472
|
+
content={"error": None, "message": "Password updated successfully."}
|
|
478
473
|
)
|
|
479
474
|
if mnemonic:
|
|
480
475
|
operate.update_password_with_mnemonic(mnemonic, new_password)
|
|
481
476
|
return JSONResponse(
|
|
482
477
|
content={
|
|
483
478
|
"error": None,
|
|
484
|
-
"message": "Password updated using seed phrase.",
|
|
479
|
+
"message": "Password updated successfully using seed phrase.",
|
|
485
480
|
}
|
|
486
481
|
)
|
|
487
482
|
|
|
488
483
|
return JSONResponse(
|
|
489
|
-
content={"error":
|
|
484
|
+
content={"error": "Password update failed."},
|
|
485
|
+
status_code=HTTPStatus.BAD_REQUEST,
|
|
490
486
|
)
|
|
491
487
|
except ValueError as e:
|
|
488
|
+
logger.error(f"Password update error: {e}\n{traceback.format_exc()}")
|
|
492
489
|
return JSONResponse(
|
|
493
|
-
content={"error": str(e)},
|
|
490
|
+
content={"error": f"Failed to update password: {str(e)}"},
|
|
491
|
+
status_code=HTTPStatus.BAD_REQUEST,
|
|
494
492
|
)
|
|
495
493
|
except Exception as e: # pylint: disable=broad-except
|
|
494
|
+
logger.error(f"Password update error: {e}\n{traceback.format_exc()}")
|
|
496
495
|
return JSONResponse(
|
|
497
|
-
content={"error":
|
|
496
|
+
content={"error": "Failed to update password. Please check the logs."},
|
|
498
497
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
499
498
|
)
|
|
500
499
|
|
|
@@ -503,21 +502,18 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
503
502
|
async def _validate_password(request: Request) -> t.Dict:
|
|
504
503
|
"""Validate password."""
|
|
505
504
|
if operate.user_account is None:
|
|
506
|
-
return
|
|
507
|
-
content={"error": "Account does not exist"},
|
|
508
|
-
status_code=HTTPStatus.BAD_REQUEST,
|
|
509
|
-
)
|
|
505
|
+
return ACCOUNT_NOT_FOUND_ERROR
|
|
510
506
|
|
|
511
507
|
data = await request.json()
|
|
512
508
|
if not operate.user_account.is_valid(password=data["password"]):
|
|
513
509
|
return JSONResponse(
|
|
514
|
-
content={"error": "Password is not valid"},
|
|
510
|
+
content={"error": "Password is not valid."},
|
|
515
511
|
status_code=HTTPStatus.UNAUTHORIZED,
|
|
516
512
|
)
|
|
517
513
|
|
|
518
514
|
operate.password = data["password"]
|
|
519
515
|
return JSONResponse(
|
|
520
|
-
content={"message": "Login successful"},
|
|
516
|
+
content={"message": "Login successful."},
|
|
521
517
|
status_code=HTTPStatus.OK,
|
|
522
518
|
)
|
|
523
519
|
|
|
@@ -535,16 +531,10 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
535
531
|
async def _create_wallet(request: Request) -> t.List[t.Dict]:
|
|
536
532
|
"""Create wallet"""
|
|
537
533
|
if operate.user_account is None:
|
|
538
|
-
return
|
|
539
|
-
content={"error": "Cannot create wallet; User account does not exist!"},
|
|
540
|
-
status_code=HTTPStatus.BAD_REQUEST,
|
|
541
|
-
)
|
|
534
|
+
return ACCOUNT_NOT_FOUND_ERROR
|
|
542
535
|
|
|
543
536
|
if operate.password is None:
|
|
544
|
-
return
|
|
545
|
-
content={"error": "You need to login before creating a wallet"},
|
|
546
|
-
status_code=HTTPStatus.UNAUTHORIZED,
|
|
547
|
-
)
|
|
537
|
+
return USER_NOT_LOGGED_IN_ERROR
|
|
548
538
|
|
|
549
539
|
data = await request.json()
|
|
550
540
|
ledger_type = LedgerType(data["ledger_type"])
|
|
@@ -564,23 +554,15 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
564
554
|
async def _get_private_key(request: Request) -> t.List[t.Dict]:
|
|
565
555
|
"""Get Master EOA private key."""
|
|
566
556
|
if operate.user_account is None:
|
|
567
|
-
return
|
|
568
|
-
content={
|
|
569
|
-
"error": "Cannot retrieve private key; User account does not exist!"
|
|
570
|
-
},
|
|
571
|
-
status_code=HTTPStatus.BAD_REQUEST,
|
|
572
|
-
)
|
|
557
|
+
return ACCOUNT_NOT_FOUND_ERROR
|
|
573
558
|
|
|
574
559
|
data = await request.json()
|
|
575
560
|
password = data.get("password")
|
|
576
|
-
error = None
|
|
577
561
|
if operate.password is None:
|
|
578
|
-
|
|
562
|
+
return USER_NOT_LOGGED_IN_ERROR
|
|
579
563
|
if operate.password != password:
|
|
580
|
-
error = {"error": "Password is not valid"}
|
|
581
|
-
if error is not None:
|
|
582
564
|
return JSONResponse(
|
|
583
|
-
content=error,
|
|
565
|
+
content={"error": "Password is not valid."},
|
|
584
566
|
status_code=HTTPStatus.UNAUTHORIZED,
|
|
585
567
|
)
|
|
586
568
|
|
|
@@ -618,12 +600,15 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
618
600
|
manager = operate.wallet_manager
|
|
619
601
|
if not manager.exists(ledger_type=ledger_type):
|
|
620
602
|
return JSONResponse(
|
|
621
|
-
content={"error": "
|
|
603
|
+
content={"error": "No Master EOA found for this chain."},
|
|
622
604
|
status_code=HTTPStatus.NOT_FOUND,
|
|
623
605
|
)
|
|
624
606
|
safes = manager.load(ledger_type=ledger_type).safes
|
|
625
607
|
if safes is None or safes.get(chain) is None:
|
|
626
|
-
return JSONResponse(
|
|
608
|
+
return JSONResponse(
|
|
609
|
+
content={"error": "No Master Safe found for this chain."},
|
|
610
|
+
status_code=HTTPStatus.NOT_FOUND,
|
|
611
|
+
)
|
|
627
612
|
|
|
628
613
|
return JSONResponse(
|
|
629
614
|
content={
|
|
@@ -637,23 +622,17 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
637
622
|
) -> t.List[t.Dict]:
|
|
638
623
|
"""Create wallet safe"""
|
|
639
624
|
if operate.user_account is None:
|
|
640
|
-
return
|
|
641
|
-
content={"error": "Cannot create safe; User account does not exist!"},
|
|
642
|
-
status_code=HTTPStatus.BAD_REQUEST,
|
|
643
|
-
)
|
|
625
|
+
return ACCOUNT_NOT_FOUND_ERROR
|
|
644
626
|
|
|
645
627
|
if operate.password is None:
|
|
646
|
-
return
|
|
647
|
-
content={"error": "You need to login before creating a safe"},
|
|
648
|
-
status_code=HTTPStatus.UNAUTHORIZED,
|
|
649
|
-
)
|
|
628
|
+
return USER_NOT_LOGGED_IN_ERROR
|
|
650
629
|
|
|
651
630
|
data = await request.json()
|
|
652
631
|
|
|
653
632
|
if "initial_funds" in data and "transfer_excess_assets" in data:
|
|
654
633
|
return JSONResponse(
|
|
655
634
|
content={
|
|
656
|
-
"error": "
|
|
635
|
+
"error": "Only specify one of 'initial_funds' or 'transfer_excess_assets', but not both."
|
|
657
636
|
},
|
|
658
637
|
status_code=HTTPStatus.BAD_REQUEST,
|
|
659
638
|
)
|
|
@@ -664,14 +643,17 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
664
643
|
ledger_type = chain.ledger_type
|
|
665
644
|
manager = operate.wallet_manager
|
|
666
645
|
if not manager.exists(ledger_type=ledger_type):
|
|
667
|
-
return JSONResponse(
|
|
646
|
+
return JSONResponse(
|
|
647
|
+
content={"error": "No Master EOA found for this chain."},
|
|
648
|
+
status_code=HTTPStatus.NOT_FOUND,
|
|
649
|
+
)
|
|
668
650
|
|
|
669
651
|
wallet = manager.load(ledger_type=ledger_type)
|
|
670
652
|
if wallet.safes is not None and wallet.safes.get(chain) is not None:
|
|
671
653
|
return JSONResponse(
|
|
672
654
|
content={
|
|
673
655
|
"safe": wallet.safes.get(chain),
|
|
674
|
-
"message":
|
|
656
|
+
"message": "Safe already exists for this chain.",
|
|
675
657
|
}
|
|
676
658
|
)
|
|
677
659
|
|
|
@@ -725,14 +707,15 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
725
707
|
"create_tx": create_tx,
|
|
726
708
|
"transfer_txs": transfer_txs,
|
|
727
709
|
"safe": safes.get(chain),
|
|
728
|
-
"message": "Safe created
|
|
729
|
-
}
|
|
710
|
+
"message": "Safe created successfully",
|
|
711
|
+
},
|
|
712
|
+
status_code=HTTPStatus.CREATED,
|
|
730
713
|
)
|
|
731
714
|
except Exception as e: # pylint: disable=broad-except
|
|
732
|
-
logger.error(traceback.format_exc())
|
|
715
|
+
logger.error(f"Safe creation failed: {e}\n{traceback.format_exc()}")
|
|
733
716
|
return JSONResponse(
|
|
734
717
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
735
|
-
content={"error":
|
|
718
|
+
content={"error": "Failed to create safe. Please check the logs."},
|
|
736
719
|
)
|
|
737
720
|
|
|
738
721
|
@app.put("/api/wallet/safe")
|
|
@@ -741,22 +724,16 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
741
724
|
"""Update wallet safe"""
|
|
742
725
|
# TODO: Extract login check as decorator
|
|
743
726
|
if operate.user_account is None:
|
|
744
|
-
return
|
|
745
|
-
content={"error": "Cannot update safe; User account does not exist!"},
|
|
746
|
-
status_code=HTTPStatus.BAD_REQUEST,
|
|
747
|
-
)
|
|
727
|
+
return ACCOUNT_NOT_FOUND_ERROR
|
|
748
728
|
|
|
749
729
|
if operate.password is None:
|
|
750
|
-
return
|
|
751
|
-
content={"error": "You need to login before updating a safe."},
|
|
752
|
-
status_code=HTTPStatus.UNAUTHORIZED,
|
|
753
|
-
)
|
|
730
|
+
return USER_NOT_LOGGED_IN_ERROR
|
|
754
731
|
|
|
755
732
|
data = await request.json()
|
|
756
733
|
|
|
757
734
|
if "chain" not in data:
|
|
758
735
|
return JSONResponse(
|
|
759
|
-
content={"error": "
|
|
736
|
+
content={"error": "'chain' is required."},
|
|
760
737
|
status_code=HTTPStatus.BAD_REQUEST,
|
|
761
738
|
)
|
|
762
739
|
|
|
@@ -765,7 +742,7 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
765
742
|
manager = operate.wallet_manager
|
|
766
743
|
if not manager.exists(ledger_type=ledger_type):
|
|
767
744
|
return JSONResponse(
|
|
768
|
-
content={"error": "
|
|
745
|
+
content={"error": "No Master EOA found for this chain."},
|
|
769
746
|
status_code=HTTPStatus.BAD_REQUEST,
|
|
770
747
|
)
|
|
771
748
|
|
|
@@ -778,12 +755,12 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
778
755
|
|
|
779
756
|
backup_owner_updated = wallet.update_backup_owner(
|
|
780
757
|
chain=chain,
|
|
781
|
-
backup_owner=backup_owner,
|
|
758
|
+
backup_owner=backup_owner,
|
|
782
759
|
)
|
|
783
760
|
message = (
|
|
784
|
-
"Backup owner updated
|
|
761
|
+
"Backup owner updated successfully"
|
|
785
762
|
if backup_owner_updated
|
|
786
|
-
else "
|
|
763
|
+
else "Backup owner is already set to this address"
|
|
787
764
|
)
|
|
788
765
|
return JSONResponse(
|
|
789
766
|
content={
|
|
@@ -968,7 +945,7 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
968
945
|
withdrawal_address = (await request.json()).get("withdrawal_address")
|
|
969
946
|
if withdrawal_address is None:
|
|
970
947
|
return JSONResponse(
|
|
971
|
-
content={"error": "withdrawal_address is required"},
|
|
948
|
+
content={"error": "'withdrawal_address' is required"},
|
|
972
949
|
status_code=HTTPStatus.BAD_REQUEST,
|
|
973
950
|
)
|
|
974
951
|
|
|
@@ -1010,13 +987,13 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
1010
987
|
from_safe=False,
|
|
1011
988
|
)
|
|
1012
989
|
except Exception as e: # pylint: disable=broad-except
|
|
1013
|
-
logger.error(traceback.format_exc())
|
|
990
|
+
logger.error(f"Withdrawal failed: {e}\n{traceback.format_exc()}")
|
|
1014
991
|
return JSONResponse(
|
|
1015
992
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
1016
|
-
content={"error":
|
|
993
|
+
content={"error": "Failed to withdraw funds. Please check the logs."},
|
|
1017
994
|
)
|
|
1018
995
|
|
|
1019
|
-
return JSONResponse(content={"error": None})
|
|
996
|
+
return JSONResponse(content={"error": None, "message": "Withdrawal successful"})
|
|
1020
997
|
|
|
1021
998
|
@app.post("/api/bridge/bridge_refill_requirements")
|
|
1022
999
|
@with_retries
|
|
@@ -1037,19 +1014,26 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
1037
1014
|
status_code=HTTPStatus.OK,
|
|
1038
1015
|
)
|
|
1039
1016
|
except ValueError as e:
|
|
1017
|
+
logger.error(f"Bridge refill requirements error: {e}")
|
|
1040
1018
|
return JSONResponse(
|
|
1041
|
-
content={"error":
|
|
1019
|
+
content={"error": "Invalid bridge request parameters."},
|
|
1020
|
+
status_code=HTTPStatus.BAD_REQUEST,
|
|
1042
1021
|
)
|
|
1043
1022
|
except Exception as e: # pylint: disable=broad-except
|
|
1023
|
+
logger.error(
|
|
1024
|
+
f"Bridge refill requirements error: {e}\n{traceback.format_exc()}"
|
|
1025
|
+
)
|
|
1044
1026
|
return JSONResponse(
|
|
1045
|
-
content={
|
|
1027
|
+
content={
|
|
1028
|
+
"error": "Failed to get bridge requirements. Please check the logs."
|
|
1029
|
+
},
|
|
1046
1030
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
1047
1031
|
)
|
|
1048
1032
|
|
|
1049
1033
|
@app.post("/api/bridge/execute")
|
|
1050
1034
|
@with_retries
|
|
1051
1035
|
async def _bridge_execute(request: Request) -> JSONResponse:
|
|
1052
|
-
"""
|
|
1036
|
+
"""Execute bridge transaction."""
|
|
1053
1037
|
if operate.password is None:
|
|
1054
1038
|
return USER_NOT_LOGGED_IN_ERROR
|
|
1055
1039
|
|
|
@@ -1062,12 +1046,17 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
1062
1046
|
status_code=HTTPStatus.OK,
|
|
1063
1047
|
)
|
|
1064
1048
|
except ValueError as e:
|
|
1049
|
+
logger.error(f"Bridge execute error: {e}")
|
|
1065
1050
|
return JSONResponse(
|
|
1066
|
-
content={"error":
|
|
1051
|
+
content={"error": "Invalid bundle ID or transaction failed."},
|
|
1052
|
+
status_code=HTTPStatus.BAD_REQUEST,
|
|
1067
1053
|
)
|
|
1068
1054
|
except Exception as e: # pylint: disable=broad-except
|
|
1055
|
+
logger.error(f"Bridge execute error: {e}\n{traceback.format_exc()}")
|
|
1069
1056
|
return JSONResponse(
|
|
1070
|
-
content={
|
|
1057
|
+
content={
|
|
1058
|
+
"error": "Failed to execute bridge transaction. Please check the logs."
|
|
1059
|
+
},
|
|
1071
1060
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
1072
1061
|
)
|
|
1073
1062
|
|
|
@@ -1081,7 +1070,7 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
1081
1070
|
@app.get("/api/bridge/status/{id}")
|
|
1082
1071
|
@with_retries
|
|
1083
1072
|
async def _bridge_status(request: Request) -> JSONResponse:
|
|
1084
|
-
"""Get
|
|
1073
|
+
"""Get bridge transaction status."""
|
|
1085
1074
|
|
|
1086
1075
|
quote_bundle_id = request.path_params["id"]
|
|
1087
1076
|
|
|
@@ -1093,12 +1082,17 @@ def create_app( # pylint: disable=too-many-locals, unused-argument, too-many-st
|
|
|
1093
1082
|
status_code=HTTPStatus.OK,
|
|
1094
1083
|
)
|
|
1095
1084
|
except ValueError as e:
|
|
1085
|
+
logger.error(f"Bridge status error: {e}")
|
|
1096
1086
|
return JSONResponse(
|
|
1097
|
-
content={"error":
|
|
1087
|
+
content={"error": "Invalid bundle ID."},
|
|
1088
|
+
status_code=HTTPStatus.BAD_REQUEST,
|
|
1098
1089
|
)
|
|
1099
1090
|
except Exception as e: # pylint: disable=broad-except
|
|
1091
|
+
logger.error(f"Bridge status error: {e}\n{traceback.format_exc()}")
|
|
1100
1092
|
return JSONResponse(
|
|
1101
|
-
content={
|
|
1093
|
+
content={
|
|
1094
|
+
"error": "Failed to get bridge status. Please check the logs."
|
|
1095
|
+
},
|
|
1102
1096
|
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
|
|
1103
1097
|
)
|
|
1104
1098
|
|
|
@@ -1114,20 +1108,35 @@ def _operate() -> None:
|
|
|
1114
1108
|
def _daemon(
|
|
1115
1109
|
host: Annotated[str, params.String(help="HTTP server host string")] = "localhost",
|
|
1116
1110
|
port: Annotated[int, params.Integer(help="HTTP server port")] = 8000,
|
|
1111
|
+
ssl_keyfile: Annotated[str, params.String(help="Path to SSL key file")] = "",
|
|
1112
|
+
ssl_certfile: Annotated[
|
|
1113
|
+
str, params.String(help="Path to SSL certificate file")
|
|
1114
|
+
] = "",
|
|
1117
1115
|
home: Annotated[
|
|
1118
1116
|
t.Optional[Path], params.Directory(long_flag="--home", help="Home directory")
|
|
1119
1117
|
] = None,
|
|
1120
1118
|
) -> None:
|
|
1121
1119
|
"""Launch operate daemon."""
|
|
1122
1120
|
app = create_app(home=home)
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1121
|
+
logger = setup_logger(name="daemon")
|
|
1122
|
+
|
|
1123
|
+
config_kwargs = {
|
|
1124
|
+
"app": app,
|
|
1125
|
+
"host": host,
|
|
1126
|
+
"port": port,
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
# Use SSL certificates if ssl_keyfile and ssl_certfile are provided
|
|
1130
|
+
if ssl_keyfile and ssl_certfile:
|
|
1131
|
+
logger.info(f"Using SSL certificates: {ssl_certfile}")
|
|
1132
|
+
config_kwargs.update(
|
|
1133
|
+
{
|
|
1134
|
+
"ssl_keyfile": ssl_keyfile,
|
|
1135
|
+
"ssl_certfile": ssl_certfile,
|
|
1136
|
+
}
|
|
1129
1137
|
)
|
|
1130
|
-
|
|
1138
|
+
|
|
1139
|
+
server = Server(Config(**config_kwargs))
|
|
1131
1140
|
app._server = server # pylint: disable=protected-access
|
|
1132
1141
|
server.run()
|
|
1133
1142
|
|
operate/ledger/profiles.py
CHANGED
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
|
|
20
20
|
"""Chain profiles."""
|
|
21
21
|
|
|
22
|
-
import enum
|
|
23
22
|
import typing as t
|
|
24
23
|
|
|
25
24
|
from operate.constants import ZERO_ADDRESS
|
|
@@ -156,26 +155,15 @@ STAKING: t.Dict[Chain, t.Dict[str, str]] = {
|
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
|
|
159
|
-
|
|
160
|
-
""
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return self.value
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
DEFAULT_PRIORITY_MECH_ADDRESS = {
|
|
172
|
-
StakingProgramMechType.LEGACY_MECH: "0x77af31De935740567Cf4fF1986D04B2c964A786a",
|
|
173
|
-
StakingProgramMechType.LEGACY_MECH_MARKETPLACE: "0x552cEA7Bc33CbBEb9f1D90c1D11D2C6daefFd053",
|
|
174
|
-
StakingProgramMechType.MECH_MARKETPLACE: "0xC05e7412439bD7e91730a6880E18d5D5873F632C",
|
|
175
|
-
}
|
|
176
|
-
DEFAULT_PRIORITY_MECH_SERVICE_ID = {
|
|
177
|
-
StakingProgramMechType.LEGACY_MECH_MARKETPLACE: 975,
|
|
178
|
-
StakingProgramMechType.MECH_MARKETPLACE: 2182,
|
|
158
|
+
DEFAULT_PRIORITY_MECH = { # maps mech marketplace address to its default priority mech address and service id
|
|
159
|
+
"0x4554fE75c1f5576c1d7F765B2A036c199Adae329": (
|
|
160
|
+
"0x552cEA7Bc33CbBEb9f1D90c1D11D2C6daefFd053",
|
|
161
|
+
975,
|
|
162
|
+
),
|
|
163
|
+
"0x735FAAb1c4Ec41128c367AFb5c3baC73509f70bB": (
|
|
164
|
+
"0xC05e7412439bD7e91730a6880E18d5D5873F632C",
|
|
165
|
+
2182,
|
|
166
|
+
),
|
|
179
167
|
}
|
|
180
168
|
|
|
181
169
|
|
|
@@ -269,17 +257,3 @@ def get_staking_contract(
|
|
|
269
257
|
staking_program_id,
|
|
270
258
|
staking_program_id,
|
|
271
259
|
)
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
def get_staking_program_mech_type(
|
|
275
|
-
staking_program_id: t.Optional[str],
|
|
276
|
-
) -> StakingProgramMechType:
|
|
277
|
-
"""Get the staking program mech type based on the staking program ID."""
|
|
278
|
-
if staking_program_id is None:
|
|
279
|
-
return StakingProgramMechType.LEGACY_MECH
|
|
280
|
-
|
|
281
|
-
if staking_program_id.startswith("quickstart_beta_mech_marketplace_expert"):
|
|
282
|
-
return StakingProgramMechType.MECH_MARKETPLACE
|
|
283
|
-
if "mech_marketplace" in staking_program_id:
|
|
284
|
-
return StakingProgramMechType.LEGACY_MECH_MARKETPLACE
|
|
285
|
-
return StakingProgramMechType.LEGACY_MECH
|
operate/operate_types.py
CHANGED
|
@@ -329,3 +329,13 @@ class AssetFundingValues(TypedDict):
|
|
|
329
329
|
|
|
330
330
|
|
|
331
331
|
FundingValues = t.Dict[str, AssetFundingValues] # str is the asset address
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
@dataclass
|
|
335
|
+
class MechMarketplaceConfig:
|
|
336
|
+
"""Mech Marketplace config."""
|
|
337
|
+
|
|
338
|
+
use_mech_marketplace: bool
|
|
339
|
+
mech_marketplace_address: str
|
|
340
|
+
priority_mech_address: str
|
|
341
|
+
priority_mech_service_id: int
|
|
@@ -73,7 +73,7 @@ def claim_staking_rewards(operate: "OperateApp", config_path: str) -> None:
|
|
|
73
73
|
config = configure_local_config(template, operate)
|
|
74
74
|
manager = operate.service_manager()
|
|
75
75
|
service = get_service(manager, template)
|
|
76
|
-
ask_password_if_needed(operate
|
|
76
|
+
ask_password_if_needed(operate)
|
|
77
77
|
|
|
78
78
|
# reload manger and config after setting operate.password
|
|
79
79
|
manager = operate.service_manager()
|
|
@@ -82,7 +82,7 @@ def reset_staking(operate: "OperateApp", config_path: str) -> None:
|
|
|
82
82
|
print("Cancelled.")
|
|
83
83
|
return
|
|
84
84
|
|
|
85
|
-
ask_password_if_needed(operate
|
|
85
|
+
ask_password_if_needed(operate)
|
|
86
86
|
manager = operate.service_manager()
|
|
87
87
|
service = get_service(manager, template)
|
|
88
88
|
|
|
@@ -37,14 +37,7 @@ from operate.account.user import UserAccount
|
|
|
37
37
|
from operate.constants import IPFS_ADDRESS, OPERATE_HOME
|
|
38
38
|
from operate.data import DATA_DIR
|
|
39
39
|
from operate.data.contracts.staking_token.contract import StakingTokenContract
|
|
40
|
-
from operate.ledger.profiles import
|
|
41
|
-
DEFAULT_PRIORITY_MECH_ADDRESS,
|
|
42
|
-
DEFAULT_PRIORITY_MECH_SERVICE_ID,
|
|
43
|
-
NO_STAKING_PROGRAM_ID,
|
|
44
|
-
STAKING,
|
|
45
|
-
get_staking_contract,
|
|
46
|
-
get_staking_program_mech_type,
|
|
47
|
-
)
|
|
40
|
+
from operate.ledger.profiles import NO_STAKING_PROGRAM_ID, STAKING, get_staking_contract
|
|
48
41
|
from operate.operate_types import (
|
|
49
42
|
Chain,
|
|
50
43
|
LedgerType,
|
|
@@ -208,9 +201,6 @@ def configure_local_config(
|
|
|
208
201
|
)
|
|
209
202
|
os.environ[f"{chain.upper()}_LEDGER_RPC"] = config.rpc[chain]
|
|
210
203
|
|
|
211
|
-
if config.password_migrated is None:
|
|
212
|
-
config.password_migrated = False
|
|
213
|
-
|
|
214
204
|
config.principal_chain = template["home_chain"]
|
|
215
205
|
|
|
216
206
|
home_chain = Chain.from_string(config.principal_chain)
|
|
@@ -396,15 +386,18 @@ def configure_local_config(
|
|
|
396
386
|
):
|
|
397
387
|
print_section("Please enter the arguments that will be used by the service.")
|
|
398
388
|
|
|
399
|
-
|
|
389
|
+
service_manager = operate.service_manager()
|
|
390
|
+
mech_configs = service_manager.get_mech_configs(
|
|
391
|
+
chain=config.principal_chain,
|
|
392
|
+
ledger_api=ledger_api,
|
|
393
|
+
staking_program_id=config.staking_program_id,
|
|
394
|
+
)
|
|
400
395
|
|
|
401
396
|
for env_var_name, env_var_data in template["env_variables"].items():
|
|
402
397
|
if env_var_data["provision_type"] == ServiceEnvProvisionType.USER:
|
|
403
398
|
# PRIORITY_MECH_ADDRESS and PRIORITY_MECH_SERVICE_ID are given dynamic default values
|
|
404
399
|
if env_var_name == "PRIORITY_MECH_ADDRESS":
|
|
405
|
-
env_var_data["value"] =
|
|
406
|
-
staking_program_mech_type
|
|
407
|
-
]
|
|
400
|
+
env_var_data["value"] = mech_configs.priority_mech_address
|
|
408
401
|
if (
|
|
409
402
|
env_var_name in config.user_provided_args
|
|
410
403
|
and env_var_data["value"] != config.user_provided_args[env_var_name]
|
|
@@ -412,9 +405,7 @@ def configure_local_config(
|
|
|
412
405
|
del config.user_provided_args[env_var_name]
|
|
413
406
|
|
|
414
407
|
if env_var_name == "PRIORITY_MECH_SERVICE_ID":
|
|
415
|
-
env_var_data["value"] =
|
|
416
|
-
DEFAULT_PRIORITY_MECH_SERVICE_ID.get(staking_program_mech_type, 0)
|
|
417
|
-
)
|
|
408
|
+
env_var_data["value"] = mech_configs.priority_mech_service_id
|
|
418
409
|
if (
|
|
419
410
|
env_var_name in config.user_provided_args
|
|
420
411
|
and env_var_data["value"] != config.user_provided_args[env_var_name]
|
|
@@ -456,7 +447,7 @@ def configure_local_config(
|
|
|
456
447
|
return config
|
|
457
448
|
|
|
458
449
|
|
|
459
|
-
def ask_password_if_needed(operate: "OperateApp"
|
|
450
|
+
def ask_password_if_needed(operate: "OperateApp") -> None:
|
|
460
451
|
"""Ask password if needed."""
|
|
461
452
|
if operate.user_account is None:
|
|
462
453
|
print_section("Set up local user account")
|
|
@@ -466,8 +457,6 @@ def ask_password_if_needed(operate: "OperateApp", config: QuickstartConfig) -> N
|
|
|
466
457
|
password=password,
|
|
467
458
|
path=operate._path / "user.json",
|
|
468
459
|
)
|
|
469
|
-
config.password_migrated = True
|
|
470
|
-
config.store()
|
|
471
460
|
else:
|
|
472
461
|
_password = None
|
|
473
462
|
while _password is None:
|
|
@@ -620,8 +609,8 @@ def _ask_funds_from_requirements(
|
|
|
620
609
|
return False
|
|
621
610
|
|
|
622
611
|
|
|
623
|
-
def
|
|
624
|
-
"""
|
|
612
|
+
def _maybe_create_master_eoa(operate: "OperateApp") -> None:
|
|
613
|
+
"""Maybe create the Master EOA."""
|
|
625
614
|
if not operate.wallet_manager.exists(ledger_type=LedgerType.ETHEREUM):
|
|
626
615
|
print("Creating the Master EOA...")
|
|
627
616
|
wallet, mnemonic = operate.wallet_manager.create(
|
|
@@ -636,9 +625,12 @@ def ensure_enough_funds(operate: "OperateApp", service: Service) -> None:
|
|
|
636
625
|
ask_or_get_from_env(
|
|
637
626
|
"Press enter to continue...", False, "CONTINUE", raise_if_missing=False
|
|
638
627
|
)
|
|
639
|
-
else:
|
|
640
|
-
wallet = operate.wallet_manager.load(ledger_type=LedgerType.ETHEREUM)
|
|
641
628
|
|
|
629
|
+
|
|
630
|
+
def ensure_enough_funds(operate: "OperateApp", service: Service) -> None:
|
|
631
|
+
"""Ensure enough funds."""
|
|
632
|
+
_maybe_create_master_eoa(operate)
|
|
633
|
+
wallet = operate.wallet_manager.load(ledger_type=LedgerType.ETHEREUM)
|
|
642
634
|
manager = operate.service_manager()
|
|
643
635
|
|
|
644
636
|
backup_owner = None
|
|
@@ -677,11 +669,12 @@ def run_service(
|
|
|
677
669
|
|
|
678
670
|
operate.service_manager().migrate_service_configs()
|
|
679
671
|
operate.wallet_manager.migrate_wallet_configs()
|
|
672
|
+
ask_password_if_needed(operate)
|
|
673
|
+
_maybe_create_master_eoa(operate)
|
|
680
674
|
|
|
681
675
|
config = configure_local_config(template, operate)
|
|
682
676
|
manager = operate.service_manager()
|
|
683
677
|
service = get_service(manager, template)
|
|
684
|
-
ask_password_if_needed(operate, config)
|
|
685
678
|
|
|
686
679
|
# reload manger and config after setting operate.password
|
|
687
680
|
manager = operate.service_manager(skip_dependency_check=skip_dependency_check)
|
|
@@ -62,7 +62,7 @@ def terminate_service(operate: "OperateApp", config_path: str) -> None:
|
|
|
62
62
|
return
|
|
63
63
|
|
|
64
64
|
config = configure_local_config(template, operate)
|
|
65
|
-
ask_password_if_needed(operate
|
|
65
|
+
ask_password_if_needed(operate)
|
|
66
66
|
manager = operate.service_manager()
|
|
67
67
|
service = get_service(manager, template)
|
|
68
68
|
ensure_enough_funds(operate, service)
|
operate/quickstart/utils.py
CHANGED
|
@@ -277,7 +277,6 @@ class QuickstartConfig(LocalResource):
|
|
|
277
277
|
|
|
278
278
|
path: Path
|
|
279
279
|
rpc: Optional[Dict[str, str]] = None
|
|
280
|
-
password_migrated: Optional[bool] = None
|
|
281
280
|
staking_program_id: Optional[str] = None
|
|
282
281
|
principal_chain: Optional[str] = None
|
|
283
282
|
user_provided_args: Optional[Dict[str, str]] = None
|
operate/services/agent_runner.py
CHANGED
|
@@ -71,7 +71,7 @@ AGENTS_SUPPORTED = {
|
|
|
71
71
|
owner="valory-xyz", repo="optimus", release="v0.0.103"
|
|
72
72
|
),
|
|
73
73
|
"dvilela/memeooorr": AgentRelease(
|
|
74
|
-
owner="valory-xyz", repo="meme-ooorr
|
|
74
|
+
owner="valory-xyz", repo="meme-ooorr", release="v0.0.101"
|
|
75
75
|
),
|
|
76
76
|
}
|
|
77
77
|
|
operate/services/manage.py
CHANGED
|
@@ -36,7 +36,7 @@ from pathlib import Path
|
|
|
36
36
|
import requests
|
|
37
37
|
from aea.helpers.base import IPFSHash
|
|
38
38
|
from aea.helpers.logging import setup_logger
|
|
39
|
-
from aea_ledger_ethereum import EthereumCrypto
|
|
39
|
+
from aea_ledger_ethereum import EthereumCrypto, LedgerApi
|
|
40
40
|
from autonomy.chain.base import registry_contracts
|
|
41
41
|
from autonomy.chain.config import CHAIN_PROFILES, ChainType
|
|
42
42
|
|
|
@@ -52,19 +52,18 @@ from operate.ledger import PUBLIC_RPCS, get_currency_denom
|
|
|
52
52
|
from operate.ledger.profiles import (
|
|
53
53
|
CONTRACTS,
|
|
54
54
|
DEFAULT_MASTER_EOA_FUNDS,
|
|
55
|
-
|
|
56
|
-
DEFAULT_PRIORITY_MECH_SERVICE_ID,
|
|
55
|
+
DEFAULT_PRIORITY_MECH,
|
|
57
56
|
OLAS,
|
|
58
57
|
STAKING,
|
|
59
58
|
USDC,
|
|
60
59
|
WRAPPED_NATIVE_ASSET,
|
|
61
60
|
get_staking_contract,
|
|
62
|
-
get_staking_program_mech_type,
|
|
63
61
|
)
|
|
64
62
|
from operate.operate_types import (
|
|
65
63
|
Chain,
|
|
66
64
|
FundingValues,
|
|
67
65
|
LedgerConfig,
|
|
66
|
+
MechMarketplaceConfig,
|
|
68
67
|
OnChainState,
|
|
69
68
|
ServiceEnvProvisionType,
|
|
70
69
|
ServiceTemplate,
|
|
@@ -520,6 +519,103 @@ class ServiceManager:
|
|
|
520
519
|
chain=chain,
|
|
521
520
|
)
|
|
522
521
|
|
|
522
|
+
def get_mech_configs(
|
|
523
|
+
self,
|
|
524
|
+
chain: str,
|
|
525
|
+
ledger_api: LedgerApi,
|
|
526
|
+
staking_program_id: str | None = None,
|
|
527
|
+
) -> MechMarketplaceConfig:
|
|
528
|
+
"""Get the mech configs."""
|
|
529
|
+
sftxb = self.get_eth_safe_tx_builder(
|
|
530
|
+
ledger_config=LedgerConfig(
|
|
531
|
+
chain=Chain(chain),
|
|
532
|
+
rpc=ledger_api.api.provider.endpoint_uri,
|
|
533
|
+
)
|
|
534
|
+
)
|
|
535
|
+
staking_contract = get_staking_contract(
|
|
536
|
+
chain=chain,
|
|
537
|
+
staking_program_id=staking_program_id,
|
|
538
|
+
)
|
|
539
|
+
if staking_contract is None:
|
|
540
|
+
return MechMarketplaceConfig(
|
|
541
|
+
use_mech_marketplace=False,
|
|
542
|
+
mech_marketplace_address=ZERO_ADDRESS,
|
|
543
|
+
priority_mech_address=ZERO_ADDRESS,
|
|
544
|
+
priority_mech_service_id=0,
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
target_staking_params = sftxb.get_staking_params(
|
|
548
|
+
staking_contract=get_staking_contract(
|
|
549
|
+
chain=chain,
|
|
550
|
+
staking_program_id=staking_program_id,
|
|
551
|
+
),
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
try:
|
|
555
|
+
# Try if activity checker is a MechActivityChecker contract
|
|
556
|
+
mech_activity_contract = t.cast(
|
|
557
|
+
MechActivityContract,
|
|
558
|
+
MechActivityContract.from_dir(
|
|
559
|
+
directory=str(DATA_DIR / "contracts" / "mech_activity")
|
|
560
|
+
),
|
|
561
|
+
)
|
|
562
|
+
|
|
563
|
+
priority_mech_address = (
|
|
564
|
+
mech_activity_contract.get_instance(
|
|
565
|
+
ledger_api=ledger_api,
|
|
566
|
+
contract_address=target_staking_params["activity_checker"],
|
|
567
|
+
)
|
|
568
|
+
.functions.agentMech()
|
|
569
|
+
.call()
|
|
570
|
+
)
|
|
571
|
+
use_mech_marketplace = False
|
|
572
|
+
mech_marketplace_address = ZERO_ADDRESS
|
|
573
|
+
priority_mech_service_id = 0
|
|
574
|
+
|
|
575
|
+
except Exception: # pylint: disable=broad-except
|
|
576
|
+
# Try if activity checker is a RequesterActivityChecker contract
|
|
577
|
+
try:
|
|
578
|
+
requester_activity_checker = t.cast(
|
|
579
|
+
RequesterActivityCheckerContract,
|
|
580
|
+
RequesterActivityCheckerContract.from_dir(
|
|
581
|
+
directory=str(
|
|
582
|
+
DATA_DIR / "contracts" / "requester_activity_checker"
|
|
583
|
+
)
|
|
584
|
+
),
|
|
585
|
+
)
|
|
586
|
+
|
|
587
|
+
mech_marketplace_address = (
|
|
588
|
+
requester_activity_checker.get_instance(
|
|
589
|
+
ledger_api=ledger_api,
|
|
590
|
+
contract_address=target_staking_params["activity_checker"],
|
|
591
|
+
)
|
|
592
|
+
.functions.mechMarketplace()
|
|
593
|
+
.call()
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
use_mech_marketplace = True
|
|
597
|
+
priority_mech_address, priority_mech_service_id = DEFAULT_PRIORITY_MECH[
|
|
598
|
+
mech_marketplace_address
|
|
599
|
+
]
|
|
600
|
+
|
|
601
|
+
except Exception as e: # pylint: disable=broad-except
|
|
602
|
+
self.logger.error(f"{e}: {traceback.format_exc()}")
|
|
603
|
+
self.logger.warning(
|
|
604
|
+
"Cannot determine type of activity checker contract. Using default parameters. "
|
|
605
|
+
"NOTE: This will be an exception in the future!"
|
|
606
|
+
)
|
|
607
|
+
priority_mech_address = "0x77af31De935740567Cf4fF1986D04B2c964A786a"
|
|
608
|
+
use_mech_marketplace = False
|
|
609
|
+
mech_marketplace_address = ZERO_ADDRESS
|
|
610
|
+
priority_mech_service_id = 0
|
|
611
|
+
|
|
612
|
+
return MechMarketplaceConfig(
|
|
613
|
+
use_mech_marketplace=use_mech_marketplace,
|
|
614
|
+
mech_marketplace_address=mech_marketplace_address,
|
|
615
|
+
priority_mech_address=priority_mech_address,
|
|
616
|
+
priority_mech_service_id=priority_mech_service_id,
|
|
617
|
+
)
|
|
618
|
+
|
|
523
619
|
def _deploy_service_onchain_from_safe( # pylint: disable=too-many-statements,too-many-locals
|
|
524
620
|
self,
|
|
525
621
|
service_config_id: str,
|
|
@@ -556,10 +652,6 @@ class ServiceManager:
|
|
|
556
652
|
self.logger.info(f"Service state: {on_chain_state.name}")
|
|
557
653
|
|
|
558
654
|
current_staking_program = self._get_current_staking_program(service, chain)
|
|
559
|
-
staking_program_mech_type = get_staking_program_mech_type(
|
|
560
|
-
user_params.staking_program_id
|
|
561
|
-
)
|
|
562
|
-
self.logger.info(f"{staking_program_mech_type=}")
|
|
563
655
|
fallback_params = dict( # nosec
|
|
564
656
|
staking_contract=NULL_ADDRESS,
|
|
565
657
|
agent_ids=[user_params.agent_id],
|
|
@@ -588,94 +680,29 @@ class ServiceManager:
|
|
|
588
680
|
# TODO A customized, arbitrary computation mechanism should be devised.
|
|
589
681
|
env_var_to_value = {}
|
|
590
682
|
if chain == service.home_chain:
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
directory=str(DATA_DIR / "contracts" / "mech_activity")
|
|
597
|
-
),
|
|
598
|
-
)
|
|
599
|
-
|
|
600
|
-
agent_mech = (
|
|
601
|
-
mech_activity_contract.get_instance(
|
|
602
|
-
ledger_api=sftxb.ledger_api,
|
|
603
|
-
contract_address=target_staking_params["activity_checker"],
|
|
604
|
-
)
|
|
605
|
-
.functions.agentMech()
|
|
606
|
-
.call()
|
|
607
|
-
)
|
|
608
|
-
use_mech_marketplace = False
|
|
609
|
-
mech_marketplace_address = ZERO_ADDRESS
|
|
610
|
-
priority_mech_address = ZERO_ADDRESS
|
|
611
|
-
priority_mech_service_id = DEFAULT_PRIORITY_MECH_SERVICE_ID.get(
|
|
612
|
-
staking_program_mech_type, 0
|
|
613
|
-
)
|
|
614
|
-
|
|
615
|
-
except Exception: # pylint: disable=broad-except
|
|
616
|
-
# Try if activity checker is a RequesterActivityChecker contract
|
|
617
|
-
try:
|
|
618
|
-
requester_activity_checker = t.cast(
|
|
619
|
-
RequesterActivityCheckerContract,
|
|
620
|
-
RequesterActivityCheckerContract.from_dir(
|
|
621
|
-
directory=str(
|
|
622
|
-
DATA_DIR / "contracts" / "requester_activity_checker"
|
|
623
|
-
)
|
|
624
|
-
),
|
|
625
|
-
)
|
|
626
|
-
|
|
627
|
-
mech_marketplace_address = (
|
|
628
|
-
requester_activity_checker.get_instance(
|
|
629
|
-
ledger_api=sftxb.ledger_api,
|
|
630
|
-
contract_address=target_staking_params["activity_checker"],
|
|
631
|
-
)
|
|
632
|
-
.functions.mechMarketplace()
|
|
633
|
-
.call()
|
|
634
|
-
)
|
|
683
|
+
mech_configs: MechMarketplaceConfig = self.get_mech_configs(
|
|
684
|
+
chain=chain,
|
|
685
|
+
ledger_api=sftxb.ledger_api,
|
|
686
|
+
staking_program_id=user_params.staking_program_id,
|
|
687
|
+
)
|
|
635
688
|
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
agent_mech = priority_mech_address = service.env_variables[
|
|
645
|
-
"PRIORITY_MECH_ADDRESS"
|
|
646
|
-
]["value"]
|
|
647
|
-
else:
|
|
648
|
-
agent_mech = (
|
|
649
|
-
priority_mech_address
|
|
650
|
-
) = DEFAULT_PRIORITY_MECH_ADDRESS[staking_program_mech_type]
|
|
651
|
-
|
|
652
|
-
if (
|
|
653
|
-
"PRIORITY_MECH_SERVICE_ID" in service.env_variables
|
|
654
|
-
and service.env_variables["PRIORITY_MECH_SERVICE_ID"][
|
|
655
|
-
"provision_type"
|
|
656
|
-
]
|
|
657
|
-
== ServiceEnvProvisionType.USER
|
|
658
|
-
):
|
|
659
|
-
priority_mech_service_id = service.env_variables[
|
|
660
|
-
"PRIORITY_MECH_SERVICE_ID"
|
|
661
|
-
]["value"]
|
|
662
|
-
else:
|
|
663
|
-
priority_mech_service_id = DEFAULT_PRIORITY_MECH_SERVICE_ID.get(
|
|
664
|
-
staking_program_mech_type, 0
|
|
665
|
-
)
|
|
689
|
+
if (
|
|
690
|
+
"PRIORITY_MECH_ADDRESS" in service.env_variables
|
|
691
|
+
and service.env_variables["PRIORITY_MECH_ADDRESS"]["provision_type"]
|
|
692
|
+
== ServiceEnvProvisionType.USER
|
|
693
|
+
):
|
|
694
|
+
mech_configs.priority_mech_address = service.env_variables[
|
|
695
|
+
"PRIORITY_MECH_ADDRESS"
|
|
696
|
+
]["value"]
|
|
666
697
|
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
use_mech_marketplace = False
|
|
676
|
-
mech_marketplace_address = ZERO_ADDRESS
|
|
677
|
-
priority_mech_address = ZERO_ADDRESS
|
|
678
|
-
priority_mech_service_id = 0
|
|
698
|
+
if (
|
|
699
|
+
"PRIORITY_MECH_SERVICE_ID" in service.env_variables
|
|
700
|
+
and service.env_variables["PRIORITY_MECH_SERVICE_ID"]["provision_type"]
|
|
701
|
+
== ServiceEnvProvisionType.USER
|
|
702
|
+
):
|
|
703
|
+
mech_configs.priority_mech_service_id = service.env_variables[
|
|
704
|
+
"PRIORITY_MECH_SERVICE_ID"
|
|
705
|
+
]["value"]
|
|
679
706
|
|
|
680
707
|
env_var_to_value.update(
|
|
681
708
|
{
|
|
@@ -693,10 +720,10 @@ class ServiceManager:
|
|
|
693
720
|
"staking_contract"
|
|
694
721
|
),
|
|
695
722
|
"MECH_MARKETPLACE_CONFIG": (
|
|
696
|
-
f'{{"mech_marketplace_address":"{mech_marketplace_address}",'
|
|
697
|
-
f'"priority_mech_address":"{priority_mech_address}",'
|
|
723
|
+
f'{{"mech_marketplace_address":"{mech_configs.mech_marketplace_address}",'
|
|
724
|
+
f'"priority_mech_address":"{mech_configs.priority_mech_address}",'
|
|
698
725
|
f'"priority_mech_staking_instance_address":"0x998dEFafD094817EF329f6dc79c703f1CF18bC90",'
|
|
699
|
-
f'"priority_mech_service_id":{priority_mech_service_id},'
|
|
726
|
+
f'"priority_mech_service_id":{mech_configs.priority_mech_service_id},'
|
|
700
727
|
f'"requester_staking_instance_address":"{target_staking_params.get("staking_contract")}",'
|
|
701
728
|
f'"response_timeout":300}}'
|
|
702
729
|
),
|
|
@@ -706,9 +733,9 @@ class ServiceManager:
|
|
|
706
733
|
"MECH_ACTIVITY_CHECKER_CONTRACT": target_staking_params.get(
|
|
707
734
|
"activity_checker"
|
|
708
735
|
),
|
|
709
|
-
"MECH_CONTRACT_ADDRESS":
|
|
736
|
+
"MECH_CONTRACT_ADDRESS": mech_configs.priority_mech_address,
|
|
710
737
|
"MECH_REQUEST_PRICE": "10000000000000000",
|
|
711
|
-
"USE_MECH_MARKETPLACE": use_mech_marketplace,
|
|
738
|
+
"USE_MECH_MARKETPLACE": mech_configs.use_mech_marketplace,
|
|
712
739
|
}
|
|
713
740
|
)
|
|
714
741
|
|
|
File without changes
|
|
File without changes
|
{olas_operate_middleware-0.7.0.dist-info → olas_operate_middleware-0.8.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|