olas-operate-middleware 0.8.1__tar.gz → 0.9.0__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 (93) hide show
  1. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/PKG-INFO +2 -2
  2. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/bridge/bridge_manager.py +3 -3
  3. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/bridge/providers/provider.py +2 -2
  4. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/bridge/providers/relay_provider.py +1 -1
  5. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/cli.py +6 -6
  6. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/constants.py +4 -9
  7. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/ledger/__init__.py +4 -4
  8. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/ledger/profiles.py +8 -8
  9. olas_operate_middleware-0.9.0/operate/migration.py +122 -0
  10. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/operate_types.py +0 -21
  11. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/analyse_logs.py +2 -2
  12. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/run_service.py +2 -2
  13. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/stop_service.py +3 -1
  14. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/utils.py +4 -7
  15. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/resource.py +37 -5
  16. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/health_checker.py +2 -6
  17. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/manage.py +13 -41
  18. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/protocol.py +5 -5
  19. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/service.py +43 -33
  20. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/utils/gnosis.py +4 -5
  21. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/wallet/master.py +4 -4
  22. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/pyproject.toml +2 -2
  23. olas_operate_middleware-0.8.1/operate/migration.py +0 -63
  24. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/LICENSE +0 -0
  25. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/README.md +0 -0
  26. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/__init__.py +0 -0
  27. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/account/__init__.py +0 -0
  28. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/account/user.py +0 -0
  29. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/bridge/providers/lifi_provider.py +0 -0
  30. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/bridge/providers/native_bridge_provider.py +0 -0
  31. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/README.md +0 -0
  32. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/__init__.py +0 -0
  33. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/__init__.py +0 -0
  34. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/dual_staking_token/__init__.py +0 -0
  35. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/dual_staking_token/build/DualStakingToken.json +0 -0
  36. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/dual_staking_token/contract.py +0 -0
  37. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/dual_staking_token/contract.yaml +0 -0
  38. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/foreign_omnibridge/__init__.py +0 -0
  39. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/foreign_omnibridge/build/ForeignOmnibridge.json +0 -0
  40. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/foreign_omnibridge/contract.py +0 -0
  41. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/foreign_omnibridge/contract.yaml +0 -0
  42. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/home_omnibridge/__init__.py +0 -0
  43. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/home_omnibridge/build/HomeOmnibridge.json +0 -0
  44. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/home_omnibridge/contract.py +0 -0
  45. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/home_omnibridge/contract.yaml +0 -0
  46. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/l1_standard_bridge/__init__.py +0 -0
  47. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/l1_standard_bridge/build/L1StandardBridge.json +0 -0
  48. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/l1_standard_bridge/contract.py +0 -0
  49. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/l1_standard_bridge/contract.yaml +0 -0
  50. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/l2_standard_bridge/__init__.py +0 -0
  51. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/l2_standard_bridge/build/L2StandardBridge.json +0 -0
  52. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/l2_standard_bridge/contract.py +0 -0
  53. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/l2_standard_bridge/contract.yaml +0 -0
  54. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/mech_activity/__init__.py +0 -0
  55. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/mech_activity/build/MechActivity.json +0 -0
  56. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/mech_activity/contract.py +0 -0
  57. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/mech_activity/contract.yaml +0 -0
  58. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/optimism_mintable_erc20/__init__.py +0 -0
  59. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/optimism_mintable_erc20/build/OptimismMintableERC20.json +0 -0
  60. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/optimism_mintable_erc20/contract.py +0 -0
  61. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/optimism_mintable_erc20/contract.yaml +0 -0
  62. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/requester_activity_checker/__init__.py +0 -0
  63. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/requester_activity_checker/build/RequesterActivityChecker.json +0 -0
  64. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/requester_activity_checker/contract.py +0 -0
  65. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/requester_activity_checker/contract.yaml +0 -0
  66. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/staking_token/__init__.py +0 -0
  67. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/staking_token/build/StakingToken.json +0 -0
  68. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/staking_token/contract.py +0 -0
  69. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/staking_token/contract.yaml +0 -0
  70. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/uniswap_v2_erc20/__init__.py +0 -0
  71. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/uniswap_v2_erc20/build/IUniswapV2ERC20.json +0 -0
  72. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/uniswap_v2_erc20/contract.py +0 -0
  73. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/uniswap_v2_erc20/contract.yaml +0 -0
  74. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/uniswap_v2_erc20/tests/__init__.py +0 -0
  75. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/data/contracts/uniswap_v2_erc20/tests/test_contract.py +0 -0
  76. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/keys.py +0 -0
  77. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/operate_http/__init__.py +0 -0
  78. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/operate_http/exceptions.py +0 -0
  79. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/pearl.py +0 -0
  80. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/claim_staking_rewards.py +1 -1
  81. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/reset_configs.py +0 -0
  82. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/reset_password.py +0 -0
  83. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/reset_staking.py +1 -1
  84. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/quickstart/terminate_on_chain_service.py +1 -1
  85. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/__init__.py +0 -0
  86. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/agent_runner.py +0 -0
  87. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/deployment_runner.py +0 -0
  88. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/utils/__init__.py +0 -0
  89. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/utils/mech.py +0 -0
  90. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/services/utils/tendermint.py +0 -0
  91. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/utils/__init__.py +0 -0
  92. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/utils/ssl.py +0 -0
  93. {olas_operate_middleware-0.8.1 → olas_operate_middleware-0.9.0}/operate/wallet/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: olas-operate-middleware
3
- Version: 0.8.1
3
+ Version: 0.9.0
4
4
  Summary:
5
5
  Author: David Vilela
6
6
  Author-email: dvilelaf@gmail.com
@@ -34,7 +34,7 @@ Requires-Dist: open-aea-cli-ipfs (==1.65.0)
34
34
  Requires-Dist: open-aea-ledger-cosmos (==1.65.0)
35
35
  Requires-Dist: open-aea-ledger-ethereum (==1.65.0)
36
36
  Requires-Dist: open-aea-ledger-ethereum-flashbots (==1.65.0)
37
- Requires-Dist: open-autonomy (>=0.19.11,<0.20.0)
37
+ Requires-Dist: open-autonomy (>=0.20.0,<0.21.0)
38
38
  Requires-Dist: psutil (>=5.9.8,<6.0.0)
39
39
  Requires-Dist: pyinstaller (>=6.8.0,<7.0.0)
40
40
  Requires-Dist: requests-toolbelt (==1.0.0)
@@ -77,7 +77,7 @@ NATIVE_BRIDGE_PROVIDER_CONFIGS: t.Dict[str, t.Any] = {
77
77
  "native-ethereum-to-optimism": {
78
78
  "from_chain": "ethereum",
79
79
  "from_bridge": "0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1",
80
- "to_chain": "optimistic",
80
+ "to_chain": "optimism",
81
81
  "to_bridge": "0x4200000000000000000000000000000000000010",
82
82
  "bridge_eta": 300,
83
83
  "bridge_contract_adaptor_class": OptimismContractAdaptor,
@@ -97,8 +97,8 @@ ROUTES = {
97
97
  (
98
98
  Chain.ETHEREUM, # from_chain
99
99
  USDC[Chain.ETHEREUM], # from_token
100
- Chain.OPTIMISTIC, # to_chain
101
- USDC[Chain.OPTIMISTIC], # to_token
100
+ Chain.OPTIMISM, # to_chain
101
+ USDC[Chain.OPTIMISM], # to_token
102
102
  ): LIFI_PROVIDER_ID,
103
103
  (
104
104
  Chain.ETHEREUM, # from_chain
@@ -231,7 +231,7 @@ class Provider(ABC):
231
231
  ledger_api = wallet.ledger_api(chain)
232
232
 
233
233
  # TODO: Backport to open aea/autonomy
234
- if chain == Chain.OPTIMISTIC:
234
+ if chain == Chain.OPTIMISM:
235
235
  ledger_api.api.middleware_onion.inject(geth_poa_middleware, layer=0)
236
236
 
237
237
  return ledger_api
@@ -244,7 +244,7 @@ class Provider(ABC):
244
244
  ledger_api = wallet.ledger_api(chain)
245
245
 
246
246
  # TODO: Backport to open aea/autonomy
247
- if chain == Chain.OPTIMISTIC:
247
+ if chain == Chain.OPTIMISM:
248
248
  ledger_api.api.middleware_onion.inject(geth_poa_middleware, layer=0)
249
249
 
250
250
  return ledger_api
@@ -91,7 +91,7 @@ RELAY_DEFAULT_GAS = {
91
91
  "swap": 1_500_000,
92
92
  "send": 1,
93
93
  },
94
- Chain.OPTIMISTIC: {
94
+ Chain.OPTIMISM: {
95
95
  "deposit": 50_000,
96
96
  "approve": 200_000,
97
97
  "authorize": 1,
@@ -47,11 +47,10 @@ from operate import services
47
47
  from operate.account.user import UserAccount
48
48
  from operate.bridge.bridge_manager import BridgeManager
49
49
  from operate.constants import (
50
- KEY,
51
- KEYS,
50
+ KEYS_DIR,
52
51
  MIN_PASSWORD_LENGTH,
53
52
  OPERATE_HOME,
54
- SERVICES,
53
+ SERVICES_DIR,
55
54
  ZERO_ADDRESS,
56
55
  )
57
56
  from operate.ledger.profiles import (
@@ -104,9 +103,8 @@ class OperateApp:
104
103
  """Initialize object."""
105
104
  super().__init__()
106
105
  self._path = (home or OPERATE_HOME).resolve()
107
- self._services = self._path / SERVICES
108
- self._keys = self._path / KEYS
109
- self._master_key = self._path / KEY
106
+ self._services = self._path / SERVICES_DIR
107
+ self._keys = self._path / KEYS_DIR
110
108
  self.setup()
111
109
 
112
110
  self.logger = logger or setup_logger(name="operate")
@@ -118,6 +116,8 @@ class OperateApp:
118
116
 
119
117
  mm = MigrationManager(self._path, self.logger)
120
118
  mm.migrate_user_account()
119
+ mm.migrate_wallets()
120
+ mm.migrate_qs_configs()
121
121
 
122
122
  def create_user_account(self, password: str) -> UserAccount:
123
123
  """Create a user account."""
@@ -24,16 +24,11 @@ from pathlib import Path
24
24
 
25
25
  OPERATE = ".operate"
26
26
  OPERATE_HOME = Path.cwd() / OPERATE
27
- CONFIG = "config.json"
28
- SERVICES = "services"
29
- KEYS = "keys"
30
- DEPLOYMENT = "deployment"
27
+ SERVICES_DIR = "services"
28
+ KEYS_DIR = "keys"
29
+ DEPLOYMENT_DIR = "deployment"
31
30
  DEPLOYMENT_JSON = "deployment.json"
32
- CONFIG = "config.json"
33
- KEY = "key"
34
- KEYS_JSON = "keys.json"
35
- DOCKER_COMPOSE_YAML = "docker-compose.yaml"
36
- SERVICE_YAML = "service.yaml"
31
+ CONFIG_JSON = "config.json"
37
32
  ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"
38
33
 
39
34
  ON_CHAIN_INTERACT_TIMEOUT = 120.0
@@ -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.OPTIMISTIC: OPTIMISM_PUBLIC_RPC,
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.OPTIMISTIC: OPTIMISM_RPC,
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.OPTIMISTIC: "ETH",
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.OPTIMISTIC: "Wei",
81
+ Chain.OPTIMISM: "Wei",
82
82
  Chain.MODE: "Wei",
83
83
  }
84
84
 
@@ -38,7 +38,7 @@ CONTRACTS: t.Dict[Chain, ContractAddresses] = {
38
38
  "multisend": "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D",
39
39
  }
40
40
  ),
41
- Chain.OPTIMISTIC: ContractAddresses(
41
+ Chain.OPTIMISM: ContractAddresses(
42
42
  {
43
43
  "service_manager": "0xFbBEc0C8b13B38a9aC0499694A69a10204c5E2aB",
44
44
  "service_registry": "0x3d77596beb0f130a4415df3D2D8232B3d3D31e44",
@@ -123,7 +123,7 @@ STAKING: t.Dict[Chain, t.Dict[str, str]] = {
123
123
  "marketplace_demand_alpha_1": "0x9d6e7aB0B5B48aE5c146936147C639fEf4575231",
124
124
  "marketplace_demand_alpha_2": "0x9fb17E549FefcCA630dd92Ea143703CeE4Ea4340",
125
125
  },
126
- Chain.OPTIMISTIC: {
126
+ Chain.OPTIMISM: {
127
127
  "optimus_alpha_1": "0x88996bbdE7f982D93214881756840cE2c77C4992",
128
128
  "optimus_alpha_2": "0xBCA056952D2A7a8dD4A002079219807CFDF9fd29",
129
129
  "optimus_alpha_3": "0x0f69f35652B1acdbD769049334f1AC580927E139",
@@ -170,7 +170,7 @@ DEFAULT_PRIORITY_MECH = { # maps mech marketplace address to its default priori
170
170
  # ERC20 token addresses
171
171
  OLAS: t.Dict[Chain, str] = {
172
172
  Chain.GNOSIS: "0xcE11e14225575945b8E6Dc0D4F2dD4C570f79d9f",
173
- Chain.OPTIMISTIC: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527",
173
+ Chain.OPTIMISM: "0xFC2E6e6BCbd49ccf3A5f029c79984372DcBFE527",
174
174
  Chain.BASE: "0x54330d28ca3357F294334BDC454a032e7f353416",
175
175
  Chain.ETHEREUM: "0x0001A500A6B18995B03f44bb040A5fFc28E45CB0",
176
176
  Chain.MODE: "0xcfD1D50ce23C46D3Cf6407487B2F8934e96DC8f9",
@@ -178,7 +178,7 @@ OLAS: t.Dict[Chain, str] = {
178
178
 
179
179
  USDC: t.Dict[Chain, str] = {
180
180
  Chain.GNOSIS: "0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83",
181
- Chain.OPTIMISTIC: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
181
+ Chain.OPTIMISM: "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85",
182
182
  Chain.BASE: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
183
183
  Chain.ETHEREUM: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
184
184
  Chain.MODE: "0xd988097fb8612cc24eeC14542bC03424c656005f",
@@ -186,7 +186,7 @@ USDC: t.Dict[Chain, str] = {
186
186
 
187
187
  WRAPPED_NATIVE_ASSET = {
188
188
  Chain.GNOSIS: "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d",
189
- Chain.OPTIMISTIC: "0x4200000000000000000000000000000000000006",
189
+ Chain.OPTIMISM: "0x4200000000000000000000000000000000000006",
190
190
  Chain.BASE: "0x4200000000000000000000000000000000000006",
191
191
  Chain.ETHEREUM: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
192
192
  Chain.MODE: "0x4200000000000000000000000000000000000006",
@@ -209,7 +209,7 @@ DEFAULT_NEW_SAFE_FUNDS: t.Dict[Chain, t.Dict[str, int]] = {
209
209
  Chain.MODE: {
210
210
  ZERO_ADDRESS: int(1e15 / 4),
211
211
  },
212
- Chain.OPTIMISTIC: {
212
+ Chain.OPTIMISM: {
213
213
  ZERO_ADDRESS: int(1e15 / 4),
214
214
  },
215
215
  }
@@ -219,7 +219,7 @@ DEFAULT_MASTER_EOA_FUNDS = {
219
219
  Chain.ETHEREUM: {ZERO_ADDRESS: 20_000_000_000_000_000},
220
220
  Chain.GNOSIS: {ZERO_ADDRESS: 1_500_000_000_000_000_000},
221
221
  Chain.MODE: {ZERO_ADDRESS: 500_000_000_000_000},
222
- Chain.OPTIMISTIC: {ZERO_ADDRESS: 5_000_000_000_000_000},
222
+ Chain.OPTIMISM: {ZERO_ADDRESS: 5_000_000_000_000_000},
223
223
  }
224
224
 
225
225
  EXPLORER_URL = {
@@ -239,7 +239,7 @@ EXPLORER_URL = {
239
239
  "tx": "https://modescan.io/tx/{tx_hash}",
240
240
  "address": "https://modescan.io/address/{address}",
241
241
  },
242
- Chain.OPTIMISTIC: {
242
+ Chain.OPTIMISM: {
243
243
  "tx": "https://optimistic.etherscan.io/tx/{tx_hash}",
244
244
  "address": "https://optimistic.etherscan.io/address/{address}",
245
245
  },
@@ -0,0 +1,122 @@
1
+ # -*- coding: utf-8 -*-
2
+ # ------------------------------------------------------------------------------
3
+ #
4
+ # Copyright 2025 Valory AG
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ # ------------------------------------------------------------------------------
19
+
20
+ """Utilities for format migration"""
21
+
22
+
23
+ import json
24
+ import logging
25
+ from pathlib import Path
26
+
27
+ from operate.utils import create_backup
28
+
29
+
30
+ class MigrationManager:
31
+ """MigrationManager"""
32
+
33
+ # TODO Backport here migration for services/config.json, etc.
34
+
35
+ def __init__(
36
+ self,
37
+ home: Path,
38
+ logger: logging.Logger,
39
+ ) -> None:
40
+ """Initialize object."""
41
+ super().__init__()
42
+ self._path = home
43
+ self.logger = logger
44
+
45
+ def migrate_user_account(self) -> None:
46
+ """Migrates user.json"""
47
+
48
+ path = self._path / "user.json"
49
+ if not path.exists():
50
+ return
51
+
52
+ with open(path, "r", encoding="utf-8") as f:
53
+ data = json.load(f)
54
+
55
+ if "password_sha" not in data:
56
+ return
57
+
58
+ create_backup(path)
59
+ new_data = {"password_hash": data["password_sha"]}
60
+ with open(path, "w", encoding="utf-8") as f:
61
+ json.dump(new_data, f, indent=4)
62
+
63
+ self.logger.info("[MIGRATION MANAGER] Migrated user.json.")
64
+
65
+ def migrate_wallets(self) -> None:
66
+ """Migrates wallets."""
67
+
68
+ path = self._path / "wallets" / "ethereum.json"
69
+ if not path.exists():
70
+ return
71
+
72
+ migrated = False
73
+ with open(path, "r", encoding="utf-8") as f:
74
+ data = json.load(f)
75
+
76
+ if "optimistic" in data.get("safes", {}):
77
+ data["safes"]["optimism"] = data["safes"].pop("optimistic")
78
+ migrated = True
79
+
80
+ if "optimistic" in data.get("safe_chains"):
81
+ data["safe_chains"] = [
82
+ "optimism" if chain == "optimistic" else chain
83
+ for chain in data["safe_chains"]
84
+ ]
85
+ migrated = True
86
+
87
+ if not migrated:
88
+ return
89
+
90
+ with open(path, "w", encoding="utf-8") as f:
91
+ json.dump(data, f, indent=4)
92
+
93
+ self.logger.info("[MIGRATION MANAGER] Migrated wallets.")
94
+
95
+ def migrate_qs_configs(self) -> None:
96
+ """Migrates quickstart configs."""
97
+
98
+ for qs_config in self._path.glob("*-quickstart-config.json"):
99
+ if not qs_config.exists():
100
+ continue
101
+
102
+ migrated = False
103
+ with open(qs_config, "r", encoding="utf-8") as f:
104
+ data = json.load(f)
105
+
106
+ if "optimistic" in data.get("rpc", {}):
107
+ data["rpc"]["optimism"] = data["rpc"].pop("optimistic")
108
+ migrated = True
109
+
110
+ if "optimistic" == data.get("principal_chain", ""):
111
+ data["principal_chain"] = "optimism"
112
+ migrated = True
113
+
114
+ if not migrated:
115
+ continue
116
+
117
+ with open(qs_config, "w", encoding="utf-8") as f:
118
+ json.dump(data, f, indent=2)
119
+
120
+ self.logger.info(
121
+ "[MIGRATION MANAGER] Migrated quickstart config: %s.", qs_config.name
122
+ )
@@ -31,13 +31,6 @@ from typing_extensions import TypedDict
31
31
  from operate.resource import LocalResource
32
32
 
33
33
 
34
- _ACTIONS = {
35
- "status": 0,
36
- "build": 1,
37
- "deploy": 2,
38
- "stop": 3,
39
- }
40
-
41
34
  CHAIN_NAME_TO_CHAIN_ID["solana"] = 900
42
35
 
43
36
  _CHAIN_ID_TO_CHAIN_NAME = {
@@ -127,20 +120,6 @@ for name in dir(ChainMixin):
127
120
  setattr(Chain, name, getattr(ChainMixin, name))
128
121
 
129
122
 
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
123
  class DeploymentStatus(enum.IntEnum):
145
124
  """Status payload."""
146
125
 
@@ -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 DEPLOYMENT
28
+ from operate.constants import DEPLOYMENT_DIR
29
29
 
30
30
 
31
31
  if TYPE_CHECKING:
@@ -41,7 +41,7 @@ def find_build_directory(config_file: Path, operate: "OperateApp") -> Path:
41
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 / DEPLOYMENT
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)
@@ -100,7 +100,7 @@ QS_STAKING_PROGRAMS: t.Dict[Chain, t.Dict[str, str]] = {
100
100
  "mech_marketplace": "mech",
101
101
  "marketplace_supply_alpha": "mech",
102
102
  },
103
- Chain.OPTIMISTIC: {
103
+ Chain.OPTIMISM: {
104
104
  "optimus_alpha_2": "optimus",
105
105
  "optimus_alpha_3": "optimus",
106
106
  "optimus_alpha_4": "optimus",
@@ -414,7 +414,7 @@ def configure_local_config(
414
414
 
415
415
  if env_var_name not in config.user_provided_args:
416
416
  print(f"Description: {env_var_data['description']}")
417
- if env_var_data["value"]:
417
+ if env_var_data["value"] is not None and env_var_data["value"] != "":
418
418
  print(f"Default: {env_var_data['value']}")
419
419
 
420
420
  user_provided_arg = ask_or_get_from_env(
@@ -23,6 +23,7 @@ import warnings
23
23
  from typing import TYPE_CHECKING, cast
24
24
 
25
25
  from operate.quickstart.run_service import (
26
+ ask_password_if_needed,
26
27
  configure_local_config,
27
28
  get_service,
28
29
  load_local_config,
@@ -55,11 +56,12 @@ def stop_service(operate: "OperateApp", config_path: str) -> None:
55
56
  print("No previous agent setup found. Exiting.")
56
57
  return
57
58
 
59
+ ask_password_if_needed(operate)
58
60
  configure_local_config(template, operate)
59
61
  manager = operate.service_manager()
60
62
  service = get_service(manager, template)
61
63
  manager.stop_service_locally(
62
- service_config_id=service.service_config_id, delete=True, use_docker=True
64
+ service_config_id=service.service_config_id, use_docker=True
63
65
  )
64
66
 
65
67
  print()
@@ -35,9 +35,6 @@ from operate.operate_types import Chain
35
35
  from operate.resource import LocalResource, deserialize
36
36
 
37
37
 
38
- MAX_QUICKSTART_VERSION = 1
39
-
40
-
41
38
  def print_box(text: str, margin: int = 1, character: str = "=") -> None:
42
39
  """Print text centered within a box."""
43
40
 
@@ -119,20 +116,20 @@ CHAIN_TO_METADATA = {
119
116
  "MAX_FEE_PER_GAS": "",
120
117
  },
121
118
  },
122
- "optimistic": {
119
+ "optimism": {
123
120
  "name": "Optimism",
124
121
  "gasFundReq": unit_to_wei(0.005), # fund for master EOA
125
- "staking_bonding_token": OLAS[Chain.OPTIMISTIC],
122
+ "staking_bonding_token": OLAS[Chain.OPTIMISM],
126
123
  "token_data": {
127
124
  ZERO_ADDRESS: {
128
125
  "symbol": "ETH",
129
126
  "decimals": 18,
130
127
  },
131
- USDC[Chain.OPTIMISTIC]: {
128
+ USDC[Chain.OPTIMISM]: {
132
129
  "symbol": "USDC",
133
130
  "decimals": 6,
134
131
  },
135
- OLAS[Chain.OPTIMISTIC]: {
132
+ OLAS[Chain.OPTIMISM]: {
136
133
  "symbol": "OLAS",
137
134
  "decimals": 18,
138
135
  },
@@ -22,7 +22,9 @@
22
22
  import enum
23
23
  import json
24
24
  import os
25
+ import platform
25
26
  import shutil
27
+ import time
26
28
  import types
27
29
  import typing as t
28
30
  from dataclasses import asdict, is_dataclass
@@ -92,6 +94,23 @@ def deserialize(obj: t.Any, otype: t.Any) -> t.Any:
92
94
  return obj
93
95
 
94
96
 
97
+ def _safe_file_operation(operation: t.Callable, *args: t.Any, **kwargs: t.Any) -> None:
98
+ """Safely perform file operation with retries on Windows."""
99
+ max_retries = 3 if platform.system() == "Windows" else 1
100
+
101
+ for attempt in range(max_retries):
102
+ try:
103
+ operation(*args, **kwargs)
104
+ return
105
+ except (PermissionError, FileNotFoundError, OSError) as e:
106
+ if attempt == max_retries - 1:
107
+ raise e
108
+
109
+ if platform.system() == "Windows":
110
+ # On Windows, wait a bit and retry
111
+ time.sleep(0.1)
112
+
113
+
95
114
  class LocalResource:
96
115
  """Initialize local resource."""
97
116
 
@@ -144,9 +163,14 @@ class LocalResource:
144
163
  bak0 = path.with_name(f"{path.name}.0.bak")
145
164
 
146
165
  if path.exists() and not bak0.exists():
147
- shutil.copy2(path, bak0)
166
+ _safe_file_operation(shutil.copy2, path, bak0)
148
167
 
149
168
  tmp_path = path.parent / f".{path.name}.tmp"
169
+
170
+ # Clean up any existing tmp file
171
+ if tmp_path.exists():
172
+ _safe_file_operation(tmp_path.unlink)
173
+
150
174
  tmp_path.write_text(
151
175
  json.dumps(
152
176
  self.json,
@@ -155,15 +179,23 @@ class LocalResource:
155
179
  encoding="utf-8",
156
180
  )
157
181
 
158
- os.replace(tmp_path, path) # atomic replace to avoid corruption
182
+ # Atomic replace to avoid corruption
183
+ try:
184
+ _safe_file_operation(os.replace, tmp_path, path)
185
+ except (PermissionError, FileNotFoundError):
186
+ # On Windows, if the replace fails, clean up and skip
187
+ if platform.system() == "Windows":
188
+ _safe_file_operation(tmp_path.unlink)
189
+
159
190
  self.load(self.path) # Validate before making backup
160
191
 
192
+ # Rotate backup files
161
193
  for i in reversed(range(N_BACKUPS - 1)):
162
194
  newer = path.with_name(f"{path.name}.{i}.bak")
163
195
  older = path.with_name(f"{path.name}.{i + 1}.bak")
164
196
  if newer.exists():
165
197
  if older.exists():
166
- older.unlink()
167
- newer.rename(older)
198
+ _safe_file_operation(older.unlink)
199
+ _safe_file_operation(newer.rename, older)
168
200
 
169
- shutil.copy2(path, bak0)
201
+ _safe_file_operation(shutil.copy2, path, bak0)
@@ -33,9 +33,6 @@ from operate.constants import HEALTH_CHECK_URL
33
33
  from operate.services.manage import ServiceManager # type: ignore
34
34
 
35
35
 
36
- HTTP_OK = HTTPStatus.OK
37
-
38
-
39
36
  class HealthChecker:
40
37
  """Health checker manager."""
41
38
 
@@ -43,7 +40,6 @@ class HealthChecker:
43
40
  PORT_UP_TIMEOUT_DEFAULT = 300 # seconds
44
41
  REQUEST_TIMEOUT_DEFAULT = 90
45
42
  NUMBER_OF_FAILS_DEFAULT = 10
46
- HEALTH_CHECK_URL = HEALTH_CHECK_URL
47
43
 
48
44
  def __init__(
49
45
  self,
@@ -95,11 +91,11 @@ class HealthChecker:
95
91
  del service_config_id
96
92
  timeout = aiohttp.ClientTimeout(total=self.REQUEST_TIMEOUT_DEFAULT)
97
93
  async with aiohttp.ClientSession(timeout=timeout) as session:
98
- async with session.get(self.HEALTH_CHECK_URL) as resp:
94
+ async with session.get(HEALTH_CHECK_URL) as resp:
99
95
  try:
100
96
  status = resp.status
101
97
 
102
- if status != HTTP_OK:
98
+ if status != HTTPStatus.OK:
103
99
  # not HTTP OK -> not healthy for sure
104
100
  content = await resp.text()
105
101
  self.logger.warning(