olas-operate-middleware 0.7.0__tar.gz → 0.8.1__tar.gz

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.
Files changed (92) hide show
  1. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/PKG-INFO +1 -1
  2. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/bridge/providers/relay_provider.py +1 -1
  3. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/cli.py +114 -105
  4. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/ledger/profiles.py +9 -35
  5. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/operate_types.py +10 -0
  6. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/claim_staking_rewards.py +1 -1
  7. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/reset_staking.py +1 -1
  8. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/run_service.py +19 -26
  9. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/terminate_on_chain_service.py +1 -1
  10. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/utils.py +0 -1
  11. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/agent_runner.py +1 -1
  12. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/manage.py +126 -99
  13. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/service.py +24 -1
  14. olas_operate_middleware-0.8.1/operate/utils/ssl.py +133 -0
  15. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/pyproject.toml +1 -1
  16. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/LICENSE +0 -0
  17. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/README.md +0 -0
  18. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/__init__.py +0 -0
  19. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/account/__init__.py +0 -0
  20. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/account/user.py +0 -0
  21. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/bridge/bridge_manager.py +0 -0
  22. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/bridge/providers/lifi_provider.py +0 -0
  23. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/bridge/providers/native_bridge_provider.py +0 -0
  24. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/bridge/providers/provider.py +0 -0
  25. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/constants.py +0 -0
  26. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/README.md +0 -0
  27. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/__init__.py +0 -0
  28. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/__init__.py +0 -0
  29. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/dual_staking_token/__init__.py +0 -0
  30. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/dual_staking_token/build/DualStakingToken.json +0 -0
  31. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/dual_staking_token/contract.py +0 -0
  32. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/dual_staking_token/contract.yaml +0 -0
  33. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/foreign_omnibridge/__init__.py +0 -0
  34. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/foreign_omnibridge/build/ForeignOmnibridge.json +0 -0
  35. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/foreign_omnibridge/contract.py +0 -0
  36. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/foreign_omnibridge/contract.yaml +0 -0
  37. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/home_omnibridge/__init__.py +0 -0
  38. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/home_omnibridge/build/HomeOmnibridge.json +0 -0
  39. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/home_omnibridge/contract.py +0 -0
  40. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/home_omnibridge/contract.yaml +0 -0
  41. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/l1_standard_bridge/__init__.py +0 -0
  42. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/l1_standard_bridge/build/L1StandardBridge.json +0 -0
  43. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/l1_standard_bridge/contract.py +0 -0
  44. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/l1_standard_bridge/contract.yaml +0 -0
  45. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/l2_standard_bridge/__init__.py +0 -0
  46. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/l2_standard_bridge/build/L2StandardBridge.json +0 -0
  47. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/l2_standard_bridge/contract.py +0 -0
  48. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/l2_standard_bridge/contract.yaml +0 -0
  49. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/mech_activity/__init__.py +0 -0
  50. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/mech_activity/build/MechActivity.json +0 -0
  51. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/mech_activity/contract.py +0 -0
  52. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/mech_activity/contract.yaml +0 -0
  53. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/optimism_mintable_erc20/__init__.py +0 -0
  54. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/optimism_mintable_erc20/build/OptimismMintableERC20.json +0 -0
  55. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/optimism_mintable_erc20/contract.py +0 -0
  56. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/optimism_mintable_erc20/contract.yaml +0 -0
  57. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/requester_activity_checker/__init__.py +0 -0
  58. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/requester_activity_checker/build/RequesterActivityChecker.json +0 -0
  59. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/requester_activity_checker/contract.py +0 -0
  60. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/requester_activity_checker/contract.yaml +0 -0
  61. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/staking_token/__init__.py +0 -0
  62. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/staking_token/build/StakingToken.json +0 -0
  63. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/staking_token/contract.py +0 -0
  64. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/staking_token/contract.yaml +0 -0
  65. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/uniswap_v2_erc20/__init__.py +0 -0
  66. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/uniswap_v2_erc20/build/IUniswapV2ERC20.json +0 -0
  67. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/uniswap_v2_erc20/contract.py +0 -0
  68. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/uniswap_v2_erc20/contract.yaml +0 -0
  69. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/uniswap_v2_erc20/tests/__init__.py +0 -0
  70. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py +0 -0
  71. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/keys.py +0 -0
  72. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/ledger/__init__.py +0 -0
  73. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/migration.py +0 -0
  74. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/operate_http/__init__.py +0 -0
  75. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/operate_http/exceptions.py +0 -0
  76. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/pearl.py +0 -0
  77. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/analyse_logs.py +0 -0
  78. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/reset_configs.py +0 -0
  79. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/reset_password.py +0 -0
  80. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/quickstart/stop_service.py +0 -0
  81. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/resource.py +0 -0
  82. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/__init__.py +0 -0
  83. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/deployment_runner.py +0 -0
  84. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/health_checker.py +0 -0
  85. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/protocol.py +0 -0
  86. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/utils/__init__.py +0 -0
  87. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/utils/mech.py +0 -0
  88. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/services/utils/tendermint.py +0 -0
  89. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/utils/__init__.py +0 -0
  90. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/utils/gnosis.py +0 -0
  91. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/wallet/__init__.py +0 -0
  92. {olas_operate_middleware-0.7.0 → olas_operate_middleware-0.8.1}/operate/wallet/master.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: olas-operate-middleware
3
- Version: 0.7.0
3
+ Version: 0.8.1
4
4
  Summary:
5
5
  Author: David Vilela
6
6
  Author-email: dvilelaf@gmail.com
@@ -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
  }
@@ -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!"}, status_code=HTTPStatus.UNAUTHORIZED
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("You must provide a new password.")
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("You must provide a new password.")
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
- error = {"traceback": traceback.format_exc()}
362
- if "has active endpoints" in e.explanation:
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
- error["error"] = str(e)
366
- errors.append(error)
364
+ error_msg = "Service deployment failed. Please check the logs."
367
365
  return JSONResponse(
368
- content={"errors": errors},
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
- errors.append(
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={"errors": errors}, status_code=HTTPStatus.INTERNAL_SERVER_ERROR
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 JSONResponse(
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": "You must provide exactly one of 'old_password' or 'mnemonic' (seed phrase).",
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": "You must provide exactly one of 'old_password' or 'mnemonic' (seed phrase), but not both.",
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"Password must be at least {MIN_PASSWORD_LENGTH} characters long."
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": None, "message": "Password not updated."}
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)}, status_code=HTTPStatus.BAD_REQUEST
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": str(e), "traceback": traceback.format_exc()},
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 JSONResponse(
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 JSONResponse(
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 JSONResponse(
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 JSONResponse(
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
- error = {"error": "You need to login before retrieving the private key"}
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": "Wallet does not exist"},
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(content={"error": "No safes found"})
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 JSONResponse(
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 JSONResponse(
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": "You can only specify 'initial_funds' or 'transfer_excess_assets', but not both."
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(content={"error": "Wallet does not exist"})
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": f"Safe already exists {chain=}.",
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": str(e), "traceback": traceback.format_exc()},
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 JSONResponse(
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 JSONResponse(
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": "You need to specify a chain to update a safe."},
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": "Wallet does not exist"},
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, # Optional value, it's fine to provide 'None' (set no backup owner/remove 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 "No changes on backup owner. The backup owner provided matches the current one."
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": str(e), "traceback": traceback.format_exc()},
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": str(e)}, status_code=HTTPStatus.BAD_REQUEST
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={"error": str(e), "traceback": traceback.format_exc()},
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
- """Get the bridge refill requirements."""
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": str(e)}, status_code=HTTPStatus.BAD_REQUEST
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={"error": str(e), "traceback": traceback.format_exc()},
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 the bridge refill requirements."""
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": str(e)}, status_code=HTTPStatus.BAD_REQUEST
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={"error": str(e), "traceback": traceback.format_exc()},
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
- server = Server(
1125
- Config(
1126
- app=app,
1127
- host=host,
1128
- port=port,
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
 
@@ -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
- class StakingProgramMechType(enum.Enum):
160
- """Staking program mech type."""
161
-
162
- LEGACY_MECH = "legacy_mech"
163
- LEGACY_MECH_MARKETPLACE = "legacy_mech_marketplace"
164
- MECH_MARKETPLACE = "mech_marketplace"
165
-
166
- def __str__(self) -> str:
167
- """Get the string representation of the enum."""
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
@@ -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, config)
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, config)
85
+ ask_password_if_needed(operate)
86
86
  manager = operate.service_manager()
87
87
  service = get_service(manager, template)
88
88