olas-operate-middleware 0.8.2__py3-none-any.whl → 0.9.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: olas-operate-middleware
3
- Version: 0.8.2
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)
@@ -1,13 +1,13 @@
1
1
  operate/__init__.py,sha256=ZQhHXOo_1L9Q5Ub_2FrZ-vu3BvORBrKgK8QcJyAsYa4,870
2
2
  operate/account/__init__.py,sha256=suJ_vBMO7hLCvLYe3MVDtLXTNDd6P03og7bvUN7fZsE,804
3
3
  operate/account/user.py,sha256=y7DqqDpqgHjbVmnfL_cN0Me_JWl3Dh6GSVt2-9FdRVw,3044
4
- operate/bridge/bridge_manager.py,sha256=ZLUqrjB78F8skaGTz43WDzM3i7UQod60b19OCczlfmI,17242
4
+ operate/bridge/bridge_manager.py,sha256=n6dZoG-mtegES_EqVraSW1LHhPPZ1Idhm2v7lrBMbJo,17236
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
- operate/bridge/providers/provider.py,sha256=U-mgf02lS9g4tGgmDJZ4GQKX9kbf4bPQY-oNWsp3kUk,19813
8
- operate/bridge/providers/relay_provider.py,sha256=krwui645N-Q0xmc3goDSUxJSpJYfxX18st_GQGKlF_A,16750
9
- operate/cli.py,sha256=lhX4eViV1lKx6jlLr7pmbGiNLeq2pkqlYXupZRRh9X0,47862
10
- operate/constants.py,sha256=oFkCw3p3fPA4MDft61e_tSIxNhpqWBauUpQF3ZSn9QI,2662
7
+ operate/bridge/providers/provider.py,sha256=YGvTqp2wNgw4E35Gov8vidwbNcoaCmEOuFn20FK-QgI,19809
8
+ operate/bridge/providers/relay_provider.py,sha256=qfFiD655qZ9MK7duwOTRYCVTv1mD8u-XbqmcJMlm_ls,16748
9
+ operate/cli.py,sha256=H6Y3ewfE_96WyV8ldXJ9C9r1LrbXEUNyVVSZFptwHzY,47886
10
+ operate/constants.py,sha256=CWH2pw8YzCbl44HzbvKSaAAWgNB2-5yUgUP1VmlyNm8,2546
11
11
  operate/data/README.md,sha256=jGPyZTvg2LCGdllvmYxmFMkkkiXb6YWatbqIkcX3kv4,879
12
12
  operate/data/__init__.py,sha256=ttC51Yqk9c4ehpIgs1Qbe7aJvzkrbbdZ1ClaCxJYByE,864
13
13
  operate/data/contracts/__init__.py,sha256=_th54_WvL0ibGy-b6St0Ne9DX-fyjsh-tNOKDn-cWrg,809
@@ -54,40 +54,40 @@ operate/data/contracts/uniswap_v2_erc20/contract.yaml,sha256=XUdz-XtKtmZgLfItbO8
54
54
  operate/data/contracts/uniswap_v2_erc20/tests/__init__.py,sha256=3Arw8dsCsJz6hVOl0t9UjFASHXbV9yp3hw6x4HqgXpU,847
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
- operate/ledger/__init__.py,sha256=kC-SYcdOQcX-v4TIWpwkSdM8L0yimEmbaL33XNY4S7Q,3361
58
- operate/ledger/profiles.py,sha256=9o_04W6rjv3Dr73PUuDOfhFM1Sn4JrmHjEBwhVdHepE,12374
59
- operate/migration.py,sha256=asWzYYSLhp0QmWov1eyEb9iGjzwZNOPDed01Z3Jnnn8,1819
57
+ operate/ledger/__init__.py,sha256=ksyctDd5PU_SToN9e-_N9fAap9ZNCHw48j5hHep-erA,3353
58
+ operate/ledger/profiles.py,sha256=Mvz2D-qoXmLzM0lBmPJGLmyNfrtXPdg_QjUeVfxLRBA,12358
59
+ operate/migration.py,sha256=yeNI6OZwuvJcnqdRTrRNMutyo9mj2gb0vRW0hTV9EFU,3659
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=Ff6rpJIgoJ-wludFtW7nufAVkUyZ3_1TShCcn2KS8GQ,8228
62
+ operate/operate_types.py,sha256=x4OHOGNFCRctTdGsq7WS_d5CzQ5Lfg75qHkfgaUOivc,7895
63
63
  operate/pearl.py,sha256=yrTpSXLu_ML3qT-uNxq3kScOyo31JyxBujiSMfMUbcg,1690
64
- operate/quickstart/analyse_logs.py,sha256=18y0JRGEryLILM_Aj2nINyMlUodA42DaypjWLev1ENs,4297
65
- operate/quickstart/claim_staking_rewards.py,sha256=VVRhYQmWJ9xWigWA6vABugIllzC1VCoehnA_Wpg4DG4,4135
64
+ operate/quickstart/analyse_logs.py,sha256=ss9BdhNs2Yo_A5NUuXpfki_j-u53YklxidBecfDQJ1k,4305
65
+ operate/quickstart/claim_staking_rewards.py,sha256=i9vwUGFiFBlPMZHsRYbXj-lkf4fUpBotLQuFcQAPGyI,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=f1_cM7QJWrCySpGJyHaDvpHbd_we39fHzBAlGLfHB_M,5157
69
- operate/quickstart/run_service.py,sha256=b2194M2TRi5Me4gZnC-TpWpajeh5eAgkNGwKpHpOK1A,27292
70
- operate/quickstart/stop_service.py,sha256=ENuFBd3KaTs0NFTy-6ECrp5XI8MRJcIOUevWF82WSt4,2094
71
- operate/quickstart/terminate_on_chain_service.py,sha256=ZsUSZp-xiAaUipU3nXqZzIiu-KIX_x0r2baFdgFTeQE,3023
72
- operate/quickstart/utils.py,sha256=rv70bktB31q6uw5hNkT6u5yo0kdpG5DCQQrQ7000W80,9172
73
- operate/resource.py,sha256=iuLlUepc18XTk1rEeC3Skt1R0v6cHST9rQxR6h4Ldg0,5179
68
+ operate/quickstart/reset_staking.py,sha256=yb293RdnVRWvFlglaG_DnMCBMY0lPKMzhpOdbXKjdvY,5157
69
+ operate/quickstart/run_service.py,sha256=16mw9oUR5Vx-Q5jwLvxs3eyl9fGrWqf1mOX8dwI9u30,27334
70
+ operate/quickstart/stop_service.py,sha256=V-0htRKo_P8zdI7Vk2FJEWmez8GDLbyAHKF1hREr_BI,2145
71
+ operate/quickstart/terminate_on_chain_service.py,sha256=X96p-0dCS-cDEduQnIboOLWaSjdvDU2ec_21nNkxJSk,3023
72
+ operate/quickstart/utils.py,sha256=rmd9e7whQIsYpRKqWBEQxMA_SHrivBg6DppFY5ECtQQ,9135
73
+ operate/resource.py,sha256=E59oIVqf6B6nN4LTmf_o2iCgLFAogTLPjm_cK6kMVxg,6305
74
74
  operate/services/__init__.py,sha256=isrThS-Ccu5Sc15JZgkN4uTAVaSg-NwUUSDeTyJEqLk,855
75
75
  operate/services/agent_runner.py,sha256=6tJePUJmlRxlIugT2fDaCJHSrQlDnl1t9pbg3-7EmCQ,7560
76
76
  operate/services/deployment_runner.py,sha256=eP1bnT3PdkYtPxi-4sZ6-Wopz8u88NkeZx7vOB2vkzc,22217
77
- operate/services/health_checker.py,sha256=pXtzFTLv4PK1OSbDCZ_RnOnvX31mPYRR16tbC7BsUNw,9754
78
- operate/services/manage.py,sha256=oDp4kMBAynPYqe3b2LM4kR9xefNxPVmmvO50XwTxFZQ,110310
79
- operate/services/protocol.py,sha256=0LcZk-zzQ2hYzZAkn_KIQGgT32Bq3_UsbBl7Ert3Ho8,60157
80
- operate/services/service.py,sha256=O8rEcPBow4bJJBJHB5RkD1fRGagJ843xwrUvFusKe9c,48146
77
+ operate/services/health_checker.py,sha256=bMmEHOUpVgKea9zocOBQdzw154XGztZ-hWB_8HkQoCI,9689
78
+ operate/services/manage.py,sha256=uc9hA3GQ5_Uny6yUv_2jaVYhV4SwqT2YrkOl4h7XNNc,109537
79
+ operate/services/protocol.py,sha256=RQssnJyjHc0k1CyZCj3jxHueyJyS3nmFYw4dVQaKXzA,60157
80
+ operate/services/service.py,sha256=hwc_gTqMig5C-9lNI2EwjNdp0BASTCmb466VhTmJlQg,48809
81
81
  operate/services/utils/__init__.py,sha256=TvioaZ1mfTRUSCtrQoLNAp4WMVXyqEJqFJM4PxSQCRU,24
82
82
  operate/services/utils/mech.py,sha256=W2x4dqodivNKXjWU-Brp40QhoUHsIMyNAO7-caMoR0Q,3821
83
83
  operate/services/utils/tendermint.py,sha256=3h9nDb2Z89T0RwUr_AaVjqtymQmsu3u6DAVCfL_k1U0,25591
84
84
  operate/utils/__init__.py,sha256=cFNP2XFpjJmDLskN0SzAk5FPdqaeN2Jn4MyVbFHmH2M,3075
85
- operate/utils/gnosis.py,sha256=XG6mhCs2yW5eRgv9fZbo1XRwAnPFTmYeMyEl3kQbauA,17729
85
+ operate/utils/gnosis.py,sha256=OxWq5zMW0fuShLZS6JAOlgB_TEsNvsZECa6EfzC4_SY,17678
86
86
  operate/utils/ssl.py,sha256=O5DrDoZD4T4qQuHP8GLwWUVxQ-1qXeefGp6uDJiF2lM,4308
87
87
  operate/wallet/__init__.py,sha256=NGiozD3XhvkBi7_FaOWQ8x1thZPK4uGpokJaeDY_o2w,813
88
- operate/wallet/master.py,sha256=FQrchjWhJKgif3IXztxS0SHm7aVaAJYFQ-FEXQgxQes,31021
89
- olas_operate_middleware-0.8.2.dist-info/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
90
- olas_operate_middleware-0.8.2.dist-info/METADATA,sha256=i89MsA1eS1fGtd_px0-C7mjA87RnciD9A6DqPYO0Dig,2034
91
- olas_operate_middleware-0.8.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
92
- olas_operate_middleware-0.8.2.dist-info/entry_points.txt,sha256=dM1g2I7ODApKQFcgl5J4NGA7pfBTo6qsUTXM-j2OLlw,44
93
- olas_operate_middleware-0.8.2.dist-info/RECORD,,
88
+ operate/wallet/master.py,sha256=lKtTHi278UWuATGSM3c2VdWHUEYg8pmvw7VzxGZ8u9I,31003
89
+ olas_operate_middleware-0.9.0.dist-info/LICENSE,sha256=mdBDB-mWKV5Cz4ejBzBiKqan6Z8zVLAh9xwM64O2FW4,11339
90
+ olas_operate_middleware-0.9.0.dist-info/METADATA,sha256=sFzHUFX9CCvAfzVtbZi00_IWsF-MxVQS5xPuhIcZmeQ,2033
91
+ olas_operate_middleware-0.9.0.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
92
+ olas_operate_middleware-0.9.0.dist-info/entry_points.txt,sha256=dM1g2I7ODApKQFcgl5J4NGA7pfBTo6qsUTXM-j2OLlw,44
93
+ olas_operate_middleware-0.9.0.dist-info/RECORD,,
@@ -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,
operate/cli.py CHANGED
@@ -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."""
operate/constants.py CHANGED
@@ -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
  },
operate/migration.py CHANGED
@@ -61,3 +61,62 @@ class MigrationManager:
61
61
  json.dump(new_data, f, indent=4)
62
62
 
63
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
+ )
operate/operate_types.py CHANGED
@@ -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)
@@ -70,10 +70,10 @@ def claim_staking_rewards(operate: "OperateApp", config_path: str) -> None:
70
70
 
71
71
  print("")
72
72
 
73
+ ask_password_if_needed(operate)
73
74
  config = configure_local_config(template, operate)
74
75
  manager = operate.service_manager()
75
76
  service = get_service(manager, template)
76
- ask_password_if_needed(operate)
77
77
 
78
78
  # reload manger and config after setting operate.password
79
79
  manager = operate.service_manager()
@@ -57,6 +57,7 @@ def reset_staking(operate: "OperateApp", config_path: str) -> None:
57
57
  print("No previous agent setup found. Exiting.")
58
58
  return
59
59
 
60
+ ask_password_if_needed(operate)
60
61
  config = configure_local_config(template, operate)
61
62
  assert ( # nosec
62
63
  config.principal_chain is not None
@@ -82,7 +83,6 @@ def reset_staking(operate: "OperateApp", config_path: str) -> None:
82
83
  print("Cancelled.")
83
84
  return
84
85
 
85
- ask_password_if_needed(operate)
86
86
  manager = operate.service_manager()
87
87
  service = get_service(manager, template)
88
88
 
@@ -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()
@@ -61,8 +61,8 @@ def terminate_service(operate: "OperateApp", config_path: str) -> None:
61
61
  print("Cancelled.")
62
62
  return
63
63
 
64
- config = configure_local_config(template, operate)
65
64
  ask_password_if_needed(operate)
65
+ config = configure_local_config(template, operate)
66
66
  manager = operate.service_manager()
67
67
  service = get_service(manager, template)
68
68
  ensure_enough_funds(operate, service)
@@ -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
  },
operate/resource.py CHANGED
@@ -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(
@@ -23,7 +23,6 @@ import asyncio
23
23
  import json
24
24
  import logging
25
25
  import os
26
- import shutil
27
26
  import time
28
27
  import traceback
29
28
  import typing as t
@@ -39,8 +38,9 @@ from aea.helpers.logging import setup_logger
39
38
  from aea_ledger_ethereum import EthereumCrypto, LedgerApi
40
39
  from autonomy.chain.base import registry_contracts
41
40
  from autonomy.chain.config import CHAIN_PROFILES, ChainType
41
+ from autonomy.chain.metadata import IPFS_URI_PREFIX
42
42
 
43
- from operate.constants import ZERO_ADDRESS
43
+ from operate.constants import IPFS_ADDRESS, ZERO_ADDRESS
44
44
  from operate.data import DATA_DIR
45
45
  from operate.data.contracts.mech_activity.contract import MechActivityContract
46
46
  from operate.data.contracts.requester_activity_checker.contract import (
@@ -71,7 +71,6 @@ from operate.operate_types import (
71
71
  from operate.services.protocol import EthSafeTxBuilder, OnChainManager, StakingState
72
72
  from operate.services.service import (
73
73
  ChainConfig,
74
- DELETE_PREFIX,
75
74
  Deployment,
76
75
  NON_EXISTENT_MULTISIG,
77
76
  NON_EXISTENT_TOKEN,
@@ -80,32 +79,13 @@ from operate.services.service import (
80
79
  Service,
81
80
  )
82
81
  from operate.services.utils.mech import deploy_mech
83
- from operate.utils.gnosis import (
84
- NULL_ADDRESS,
85
- drain_eoa,
86
- get_asset_balance,
87
- get_assets_balances,
88
- )
82
+ from operate.utils.gnosis import drain_eoa, get_asset_balance, get_assets_balances
89
83
  from operate.utils.gnosis import transfer as transfer_from_safe
90
84
  from operate.utils.gnosis import transfer_erc20_from_safe
91
85
  from operate.wallet.master import MasterWalletManager
92
86
 
93
87
 
94
88
  # pylint: disable=redefined-builtin
95
-
96
- OPERATE = ".operate"
97
- CONFIG = "config.json"
98
- SERVICES = "services"
99
- KEYS = "keys"
100
- DEPLOYMENT = "deployment"
101
- CONFIG = "config.json"
102
- KEY = "master-key.txt"
103
- KEYS_JSON = "keys.json"
104
- DOCKER_COMPOSE_YAML = "docker-compose.yaml"
105
- SERVICE_YAML = "service.yaml"
106
- HTTP_OK = 200
107
- URI_HASH_POSITION = 7
108
- IPFS_GATEWAY = "https://gateway.autonolas.tech/ipfs/"
109
89
  DEFAULT_TOPUP_THRESHOLD = 0.5
110
90
  # At the moment, we only support running one agent per service locally on a machine.
111
91
  # If multiple agents are provided in the service.yaml file, only the 0th index config will be used.
@@ -297,7 +277,7 @@ class ServiceManager:
297
277
  sftxb = self.get_eth_safe_tx_builder(ledger_config=ledger_config)
298
278
  info = sftxb.info(token_id=chain_data.token)
299
279
  config_hash = info["config_hash"]
300
- url = f"{IPFS_GATEWAY}f01701220{config_hash}"
280
+ url = IPFS_ADDRESS.format(hash=config_hash)
301
281
  self.logger.info(f"Fetching {url=}...")
302
282
  res = requests.get(url, timeout=30)
303
283
  if res.status_code == HTTPStatus.OK:
@@ -403,7 +383,7 @@ class ServiceManager:
403
383
  )
404
384
 
405
385
  on_chain_metadata = self._get_on_chain_metadata(chain_config=chain_config)
406
- on_chain_hash = on_chain_metadata.get("code_uri", "")[URI_HASH_POSITION:]
386
+ on_chain_hash = on_chain_metadata.get("code_uri", "")[len(IPFS_URI_PREFIX) :]
407
387
  on_chain_description = on_chain_metadata.get("description")
408
388
 
409
389
  current_agent_bond = staking_params[
@@ -653,13 +633,13 @@ class ServiceManager:
653
633
 
654
634
  current_staking_program = self._get_current_staking_program(service, chain)
655
635
  fallback_params = dict( # nosec
656
- staking_contract=NULL_ADDRESS,
636
+ staking_contract=ZERO_ADDRESS,
657
637
  agent_ids=[user_params.agent_id],
658
638
  service_registry="0x9338b5153AE39BB89f50468E608eD9d764B755fD", # nosec
659
- staking_token=NULL_ADDRESS, # nosec
639
+ staking_token=ZERO_ADDRESS, # nosec
660
640
  service_registry_token_utility="0xa45E64d13A30a51b91ae0eb182e88a40e9b18eD8", # nosec
661
641
  min_staking_deposit=20000000000000000000,
662
- activity_checker=NULL_ADDRESS, # nosec
642
+ activity_checker=ZERO_ADDRESS, # nosec
663
643
  )
664
644
 
665
645
  current_staking_params = sftxb.get_staking_params(
@@ -710,7 +690,7 @@ class ServiceManager:
710
690
  "GNOSIS_LEDGER_RPC": PUBLIC_RPCS[Chain.GNOSIS],
711
691
  "BASE_LEDGER_RPC": PUBLIC_RPCS[Chain.BASE],
712
692
  "CELO_LEDGER_RPC": PUBLIC_RPCS[Chain.CELO],
713
- "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[Chain.OPTIMISTIC],
693
+ "OPTIMISM_LEDGER_RPC": PUBLIC_RPCS[Chain.OPTIMISM],
714
694
  "MODE_LEDGER_RPC": PUBLIC_RPCS[Chain.MODE],
715
695
  f"{chain.upper()}_LEDGER_RPC": ledger_config.rpc,
716
696
  "STAKING_CONTRACT_ADDRESS": target_staking_params.get(
@@ -792,7 +772,7 @@ class ServiceManager:
792
772
  target_staking_params["agent_ids"] = [agent_id]
793
773
 
794
774
  on_chain_metadata = self._get_on_chain_metadata(chain_config=chain_config)
795
- on_chain_hash = on_chain_metadata.get("code_uri", "")[URI_HASH_POSITION:]
775
+ on_chain_hash = on_chain_metadata.get("code_uri", "")[len(IPFS_URI_PREFIX) :]
796
776
  on_chain_description = on_chain_metadata.get("description")
797
777
 
798
778
  current_agent_bond = sftxb.get_agent_bond(
@@ -1067,7 +1047,7 @@ class ServiceManager:
1067
1047
 
1068
1048
  reuse_multisig = True
1069
1049
  info = sftxb.info(token_id=chain_data.token)
1070
- if info["multisig"] == NULL_ADDRESS:
1050
+ if info["multisig"] == ZERO_ADDRESS:
1071
1051
  reuse_multisig = False
1072
1052
 
1073
1053
  self.logger.info(f"{reuse_multisig=}")
@@ -1135,9 +1115,7 @@ class ServiceManager:
1135
1115
  staking_chain = None
1136
1116
  for chain_, config in service.chain_configs.items():
1137
1117
  if config.chain_data.user_params.use_staking:
1138
- staking_chain = chain_.replace(
1139
- "optimistic", "optimism"
1140
- ) # TODO: remove this hack, when it's renamed in open-autonomy
1118
+ staking_chain = chain_
1141
1119
  break
1142
1120
 
1143
1121
  service.update_env_variables_values(
@@ -1148,9 +1126,7 @@ class ServiceManager:
1148
1126
  for chain, config in service.chain_configs.items()
1149
1127
  },
1150
1128
  separators=(",", ":"),
1151
- ).replace(
1152
- "optimistic", "optimism"
1153
- ), # TODO: remove this hack, when it's renamed in open-autonomy
1129
+ ),
1154
1130
  "STAKING_CHAIN": staking_chain,
1155
1131
  }
1156
1132
  )
@@ -2210,10 +2186,6 @@ class ServiceManager:
2210
2186
  paths = list(self.path.iterdir())
2211
2187
  for path in paths:
2212
2188
  try:
2213
- if path.name.startswith(DELETE_PREFIX):
2214
- shutil.rmtree(path)
2215
- self.logger.info(f"Deleted folder: {path.name}")
2216
-
2217
2189
  if path.name.startswith(SERVICE_CONFIG_PREFIX) or path.name.startswith(
2218
2190
  "bafybei"
2219
2191
  ):
@@ -61,6 +61,7 @@ from operate.constants import (
61
61
  ON_CHAIN_INTERACT_RETRIES,
62
62
  ON_CHAIN_INTERACT_SLEEP,
63
63
  ON_CHAIN_INTERACT_TIMEOUT,
64
+ ZERO_ADDRESS,
64
65
  )
65
66
  from operate.data import DATA_DIR
66
67
  from operate.data.contracts.dual_staking_token.contract import DualStakingTokenContract
@@ -69,7 +70,6 @@ from operate.operate_types import Chain as OperateChain
69
70
  from operate.operate_types import ContractAddresses
70
71
  from operate.utils.gnosis import (
71
72
  MultiSendOperation,
72
- NULL_ADDRESS,
73
73
  SafeOperation,
74
74
  hash_payload_to_hex,
75
75
  skill_input_hex_to_payload,
@@ -710,7 +710,7 @@ class _ChainUtil:
710
710
  token_id=service_id,
711
711
  )
712
712
 
713
- if multisig_address == NULL_ADDRESS:
713
+ if multisig_address == ZERO_ADDRESS:
714
714
  return []
715
715
 
716
716
  return registry_contracts.gnosis_safe.get_owners(
@@ -1605,7 +1605,7 @@ def get_reuse_multisig_from_safe_payload( # pylint: disable=too-many-locals
1605
1605
  chain_type=chain_type,
1606
1606
  token_id=service_id,
1607
1607
  )
1608
- if multisig_address == NULL_ADDRESS:
1608
+ if multisig_address == ZERO_ADDRESS:
1609
1609
  return None, None, "Cannot reuse multisig, No previous deployment exist!"
1610
1610
 
1611
1611
  multisend_address = ContractConfigs.get(MULTISEND_CONTRACT.name).contracts[
@@ -1723,8 +1723,8 @@ def get_reuse_multisig_from_safe_payload( # pylint: disable=too-many-locals
1723
1723
  0, # safe tx gas
1724
1724
  0, # bas gas
1725
1725
  0, # safe gas price
1726
- NULL_ADDRESS, # gas token
1727
- NULL_ADDRESS, # refund receiver
1726
+ ZERO_ADDRESS, # gas token
1727
+ ZERO_ADDRESS, # refund receiver
1728
1728
  signature_bytes, # signatures
1729
1729
  ],
1730
1730
  )
@@ -45,7 +45,9 @@ from aea.configurations.constants import (
45
45
  from aea.helpers.yaml_utils import yaml_dump, yaml_load, yaml_load_all
46
46
  from aea_cli_ipfs.ipfs_utils import IPFSTool
47
47
  from autonomy.cli.helpers.deployment import run_deployment, stop_deployment
48
+ from autonomy.configurations.constants import DEFAULT_SERVICE_CONFIG_FILE
48
49
  from autonomy.configurations.loader import apply_env_variables, load_service_config
50
+ from autonomy.constants import DEFAULT_KEYS_FILE, DOCKER_COMPOSE_YAML
49
51
  from autonomy.deploy.base import BaseDeploymentGenerator
50
52
  from autonomy.deploy.base import ServiceBuilder as BaseServiceBuilder
51
53
  from autonomy.deploy.constants import (
@@ -61,13 +63,7 @@ from autonomy.deploy.generators.docker_compose.base import DockerComposeGenerato
61
63
  from autonomy.deploy.generators.kubernetes.base import KubernetesGenerator
62
64
  from docker import from_env
63
65
 
64
- from operate.constants import (
65
- DEPLOYMENT,
66
- DEPLOYMENT_JSON,
67
- DOCKER_COMPOSE_YAML,
68
- KEYS_JSON,
69
- ZERO_ADDRESS,
70
- )
66
+ from operate.constants import CONFIG_JSON, DEPLOYMENT_DIR, DEPLOYMENT_JSON, ZERO_ADDRESS
71
67
  from operate.keys import Keys
72
68
  from operate.operate_http.exceptions import NotAllowed
73
69
  from operate.operate_types import (
@@ -96,8 +92,7 @@ from operate.utils.ssl import create_ssl_certificate
96
92
  SAFE_CONTRACT_ADDRESS = "safe_contract_address"
97
93
  ALL_PARTICIPANTS = "all_participants"
98
94
  CONSENSUS_THRESHOLD = "consensus_threshold"
99
- DELETE_PREFIX = "delete_"
100
- SERVICE_CONFIG_VERSION = 6
95
+ SERVICE_CONFIG_VERSION = 7
101
96
  SERVICE_CONFIG_PREFIX = "sc-"
102
97
 
103
98
  NON_EXISTENT_MULTISIG = "0xm"
@@ -410,7 +405,7 @@ class Deployment(LocalResource):
410
405
  nodes: DeployedNodes
411
406
  path: Path
412
407
 
413
- _file = "deployment.json"
408
+ _file = DEPLOYMENT_JSON
414
409
 
415
410
  @staticmethod
416
411
  def new(path: Path) -> "Deployment":
@@ -435,14 +430,14 @@ class Deployment(LocalResource):
435
430
 
436
431
  def copy_previous_agent_run_logs(self) -> None:
437
432
  """Copy previous agent logs."""
438
- source_path = self.path / DEPLOYMENT / "agent" / "log.txt"
433
+ source_path = self.path / DEPLOYMENT_DIR / "agent" / "log.txt"
439
434
  destination_path = self.path / "prev_log.txt"
440
435
  if source_path.exists():
441
436
  shutil.copy(source_path, destination_path)
442
437
 
443
438
  def _build_kubernetes(self, force: bool = True) -> None:
444
439
  """Build kubernetes deployment."""
445
- k8s_build = self.path / DEPLOYMENT / "abci_build_k8s"
440
+ k8s_build = self.path / DEPLOYMENT_DIR / "abci_build_k8s"
446
441
  if k8s_build.exists() and force:
447
442
  shutil.rmtree(k8s_build)
448
443
  mkdirs(build_dir=k8s_build)
@@ -450,7 +445,7 @@ class Deployment(LocalResource):
450
445
  service = Service.load(path=self.path)
451
446
  builder = ServiceBuilder.from_dir(
452
447
  path=service.package_absolute_path,
453
- keys_file=self.path / KEYS_JSON,
448
+ keys_file=self.path / DEFAULT_KEYS_FILE,
454
449
  number_of_agents=len(service.keys),
455
450
  )
456
451
  builder.deplopyment_type = KubernetesGenerator.deployment_type
@@ -482,7 +477,7 @@ class Deployment(LocalResource):
482
477
  force=force,
483
478
  )
484
479
 
485
- build = self.path / DEPLOYMENT
480
+ build = self.path / DEPLOYMENT_DIR
486
481
  if build.exists() and not force:
487
482
  return
488
483
  if build.exists() and force:
@@ -490,7 +485,7 @@ class Deployment(LocalResource):
490
485
  shutil.rmtree(build)
491
486
  mkdirs(build_dir=build)
492
487
 
493
- keys_file = self.path / KEYS_JSON
488
+ keys_file = self.path / DEFAULT_KEYS_FILE
494
489
  keys_file.write_text(
495
490
  json.dumps(
496
491
  [
@@ -588,7 +583,7 @@ class Deployment(LocalResource):
588
583
 
589
584
  def _build_host(self, force: bool = True, chain: t.Optional[str] = None) -> None:
590
585
  """Build host depployment."""
591
- build = self.path / DEPLOYMENT
586
+ build = self.path / DEPLOYMENT_DIR
592
587
  if build.exists() and not force:
593
588
  return
594
589
 
@@ -617,7 +612,7 @@ class Deployment(LocalResource):
617
612
  chain_config = service.chain_configs[chain]
618
613
  chain_data = chain_config.chain_data
619
614
 
620
- keys_file = self.path / KEYS_JSON
615
+ keys_file = self.path / DEFAULT_KEYS_FILE
621
616
  keys_file.write_text(
622
617
  json.dumps(
623
618
  [
@@ -708,7 +703,7 @@ class Deployment(LocalResource):
708
703
  self._build_kubernetes(force=force)
709
704
  else:
710
705
  ssl_key_path, ssl_cert_path = create_ssl_certificate(
711
- ssl_dir=service.path / DEPLOYMENT / "ssl"
706
+ ssl_dir=service.path / DEPLOYMENT_DIR / "ssl"
712
707
  )
713
708
  service.update_env_variables_values(
714
709
  {
@@ -734,7 +729,11 @@ class Deployment(LocalResource):
734
729
 
735
730
  try:
736
731
  if use_docker:
737
- run_deployment(build_dir=self.path / "deployment", detach=True)
732
+ run_deployment(
733
+ build_dir=self.path / "deployment",
734
+ detach=True,
735
+ project_name=self.path.name,
736
+ )
738
737
  else:
739
738
  run_host_deployment(build_dir=self.path / "deployment")
740
739
  except Exception:
@@ -754,7 +753,10 @@ class Deployment(LocalResource):
754
753
  self.store()
755
754
 
756
755
  if use_docker:
757
- stop_deployment(build_dir=self.path / "deployment")
756
+ stop_deployment(
757
+ build_dir=self.path / "deployment",
758
+ project_name=self.path.name,
759
+ )
758
760
  else:
759
761
  stop_host_deployment(build_dir=self.path / "deployment")
760
762
 
@@ -763,7 +765,7 @@ class Deployment(LocalResource):
763
765
 
764
766
  def delete(self) -> None:
765
767
  """Delete the deployment."""
766
- build = self.path / DEPLOYMENT
768
+ build = self.path / DEPLOYMENT_DIR
767
769
  shutil.rmtree(build)
768
770
  self.status = DeploymentStatus.DELETED
769
771
  self.store()
@@ -791,7 +793,7 @@ class Service(LocalResource):
791
793
  _helper: t.Optional[ServiceHelper] = None
792
794
  _deployment: t.Optional[Deployment] = None
793
795
 
794
- _file = "config.json"
796
+ _file = CONFIG_JSON
795
797
 
796
798
  @staticmethod
797
799
  def _determine_agent_id(service_name: str) -> int:
@@ -933,7 +935,7 @@ class Service(LocalResource):
933
935
  "goerli",
934
936
  "gnosis",
935
937
  "solana",
936
- "optimistic",
938
+ "optimism",
937
939
  "base",
938
940
  "mode",
939
941
  ]
@@ -969,6 +971,19 @@ class Service(LocalResource):
969
971
  new_chain_configs[chain] = chain_data # type: ignore
970
972
  data["chain_configs"] = new_chain_configs
971
973
 
974
+ if version < 7:
975
+ if data["home_chain"] == "optimistic":
976
+ data["home_chain"] = Chain.OPTIMISM.value
977
+
978
+ if "optimistic" in data["chain_configs"]:
979
+ data["chain_configs"]["optimism"] = data["chain_configs"].pop(
980
+ "optimistic"
981
+ )
982
+
983
+ for _, chain_config in data["chain_configs"].items():
984
+ if chain_config["ledger_config"]["chain"] == "optimistic":
985
+ chain_config["ledger_config"]["chain"] = Chain.OPTIMISM.value
986
+
972
987
  data["version"] = SERVICE_CONFIG_VERSION
973
988
 
974
989
  # Redownload service path
@@ -1028,7 +1043,7 @@ class Service(LocalResource):
1028
1043
  package_absolute_path = self.path / self.package_path
1029
1044
  if (
1030
1045
  not package_absolute_path.exists()
1031
- or not (package_absolute_path / "service.yaml").exists()
1046
+ or not (package_absolute_path / DEFAULT_SERVICE_CONFIG_FILE).exists()
1032
1047
  ):
1033
1048
  with tempfile.TemporaryDirectory(dir=self.path) as temp_dir:
1034
1049
  package_temp_path = Path(
@@ -1103,7 +1118,7 @@ class Service(LocalResource):
1103
1118
 
1104
1119
  def service_public_id(self, include_version: bool = True) -> str:
1105
1120
  """Get the public id (based on the service hash)."""
1106
- with (self.package_absolute_path / "service.yaml").open(
1121
+ with (self.package_absolute_path / DEFAULT_SERVICE_CONFIG_FILE).open(
1107
1122
  "r", encoding="utf-8"
1108
1123
  ) as fp:
1109
1124
  service_yaml, *_ = yaml_load_all(fp)
@@ -1135,7 +1150,9 @@ class Service(LocalResource):
1135
1150
  )
1136
1151
  )
1137
1152
 
1138
- with (package_path / "service.yaml").open("r", encoding="utf-8") as fp:
1153
+ with (package_path / DEFAULT_SERVICE_CONFIG_FILE).open(
1154
+ "r", encoding="utf-8"
1155
+ ) as fp:
1139
1156
  service_yaml, *_ = yaml_load_all(fp)
1140
1157
 
1141
1158
  public_id = f"{service_yaml['author']}/{service_yaml['name']}"
@@ -1321,10 +1338,3 @@ class Service(LocalResource):
1321
1338
 
1322
1339
  if updated:
1323
1340
  self.store()
1324
-
1325
- def delete(self) -> None:
1326
- """Delete a service."""
1327
- parent_directory = self.path.parent
1328
- new_path = parent_directory / f"{DELETE_PREFIX}{self.path.name}"
1329
- shutil.move(self.path, new_path)
1330
- shutil.rmtree(new_path)
operate/utils/gnosis.py CHANGED
@@ -43,9 +43,7 @@ from operate.operate_types import Chain
43
43
 
44
44
 
45
45
  logger = setup_logger(name="operate.manager")
46
- NULL_ADDRESS: str = "0x" + "0" * 40
47
46
  MAX_UINT256 = 2**256 - 1
48
- ZERO_ETH = 0
49
47
  SENTINEL_OWNERS = "0x0000000000000000000000000000000000000001"
50
48
 
51
49
 
@@ -73,8 +71,8 @@ def hash_payload_to_hex( # pylint: disable=too-many-arguments,too-many-locals
73
71
  operation: int = SafeOperation.CALL.value,
74
72
  base_gas: int = 0,
75
73
  safe_gas_price: int = 0,
76
- gas_token: str = NULL_ADDRESS,
77
- refund_receiver: str = NULL_ADDRESS,
74
+ gas_token: str = ZERO_ADDRESS,
75
+ refund_receiver: str = ZERO_ADDRESS,
78
76
  use_flashbots: bool = False,
79
77
  gas_limit: int = 0,
80
78
  raise_on_failed_simulation: bool = False,
@@ -525,7 +523,7 @@ def drain_eoa(
525
523
  if Chain.from_id(chain_id) in (
526
524
  Chain.ARBITRUM_ONE,
527
525
  Chain.BASE,
528
- Chain.OPTIMISTIC,
526
+ Chain.OPTIMISM,
529
527
  Chain.MODE,
530
528
  ):
531
529
  chain_fee += ledger_api.get_l1_data_fee(tx)
operate/wallet/master.py CHANGED
@@ -48,7 +48,7 @@ from operate.ledger.profiles import ERC20_TOKENS, OLAS, USDC
48
48
  from operate.operate_types import Chain, LedgerType
49
49
  from operate.resource import LocalResource
50
50
  from operate.utils import create_backup
51
- from operate.utils.gnosis import NULL_ADDRESS, add_owner
51
+ from operate.utils.gnosis import add_owner
52
52
  from operate.utils.gnosis import create_safe as create_gnosis_safe
53
53
  from operate.utils.gnosis import (
54
54
  drain_eoa,
@@ -110,7 +110,7 @@ class MasterWallet(LocalResource):
110
110
  ) -> LedgerApi:
111
111
  """Get ledger api object."""
112
112
  gas_price_strategies = deepcopy(DEFAULT_GAS_PRICE_STRATEGIES)
113
- if chain in (Chain.BASE, Chain.MODE, Chain.OPTIMISTIC):
113
+ if chain in (Chain.BASE, Chain.MODE, Chain.OPTIMISM):
114
114
  gas_price_strategies[EIP1559]["fallback_estimate"]["maxFeePerGas"] = to_wei(
115
115
  5, GWEI
116
116
  )
@@ -717,7 +717,7 @@ class EthereumMasterWallet(MasterWallet):
717
717
  owners.remove(self.address)
718
718
 
719
719
  balances: t.Dict[str, int] = {}
720
- balances[NULL_ADDRESS] = ledger_api.get_balance(safe) or 0
720
+ balances[ZERO_ADDRESS] = ledger_api.get_balance(safe) or 0
721
721
  for token in tokens:
722
722
  balance = (
723
723
  registry_contracts.erc20.get_instance(
@@ -781,7 +781,7 @@ class EthereumMasterWallet(MasterWallet):
781
781
  "goerli",
782
782
  "gnosis",
783
783
  "solana",
784
- "optimistic",
784
+ "optimism",
785
785
  "base",
786
786
  "mode",
787
787
  ]