iwa 0.0.58__py3-none-any.whl → 0.0.59__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.
Files changed (58) hide show
  1. iwa/core/chain/interface.py +32 -21
  2. iwa/core/chain/rate_limiter.py +0 -6
  3. iwa/core/chainlist.py +15 -10
  4. iwa/core/cli.py +3 -0
  5. iwa/core/contracts/cache.py +1 -1
  6. iwa/core/contracts/contract.py +1 -0
  7. iwa/core/contracts/decoder.py +10 -4
  8. iwa/core/http.py +31 -0
  9. iwa/core/ipfs.py +11 -19
  10. iwa/core/keys.py +10 -4
  11. iwa/core/models.py +1 -3
  12. iwa/core/pricing.py +3 -21
  13. iwa/core/rpc_monitor.py +1 -0
  14. iwa/core/services/balance.py +0 -1
  15. iwa/core/services/safe.py +8 -2
  16. iwa/core/services/safe_executor.py +52 -18
  17. iwa/core/services/transaction.py +32 -12
  18. iwa/core/services/transfer/erc20.py +0 -1
  19. iwa/core/services/transfer/native.py +1 -1
  20. iwa/core/tests/test_gnosis_fee.py +6 -2
  21. iwa/core/tests/test_ipfs.py +1 -1
  22. iwa/core/tests/test_regression_fixes.py +3 -6
  23. iwa/core/utils.py +2 -0
  24. iwa/core/wallet.py +3 -1
  25. iwa/plugins/olas/constants.py +15 -5
  26. iwa/plugins/olas/contracts/activity_checker.py +3 -3
  27. iwa/plugins/olas/contracts/staking.py +0 -1
  28. iwa/plugins/olas/events.py +15 -13
  29. iwa/plugins/olas/importer.py +26 -20
  30. iwa/plugins/olas/plugin.py +16 -14
  31. iwa/plugins/olas/service_manager/drain.py +1 -3
  32. iwa/plugins/olas/service_manager/lifecycle.py +9 -9
  33. iwa/plugins/olas/service_manager/staking.py +11 -6
  34. iwa/plugins/olas/tests/test_olas_archiving.py +25 -15
  35. iwa/plugins/olas/tests/test_olas_integration.py +49 -29
  36. iwa/plugins/olas/tests/test_service_manager.py +8 -10
  37. iwa/plugins/olas/tests/test_service_manager_errors.py +5 -4
  38. iwa/plugins/olas/tests/test_service_manager_flows.py +6 -5
  39. iwa/plugins/olas/tests/test_service_staking.py +64 -38
  40. iwa/tools/drain_accounts.py +2 -1
  41. iwa/tools/reset_env.py +2 -1
  42. iwa/tools/test_chainlist.py +5 -1
  43. iwa/tui/screens/wallets.py +1 -3
  44. iwa/web/routers/olas/services.py +10 -5
  45. {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/METADATA +1 -1
  46. {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/RECORD +58 -57
  47. tests/test_balance_service.py +0 -2
  48. tests/test_chain.py +1 -2
  49. tests/test_rate_limiter_retry.py +2 -7
  50. tests/test_rpc_efficiency.py +4 -1
  51. tests/test_rpc_rate_limit.py +1 -0
  52. tests/test_rpc_rotation.py +4 -4
  53. tests/test_safe_executor.py +76 -50
  54. tests/test_safe_integration.py +11 -6
  55. {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/WHEEL +0 -0
  56. {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/entry_points.txt +0 -0
  57. {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/licenses/LICENSE +0 -0
  58. {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/top_level.txt +0 -0
@@ -429,9 +429,7 @@ class LifecycleManagerMixin:
429
429
  )
430
430
 
431
431
  if balance < bond_amount:
432
- logger.error(
433
- f"[ACTIVATE] FAIL: Owner balance {balance} < required {bond_amount}"
434
- )
432
+ logger.error(f"[ACTIVATE] FAIL: Owner balance {balance} < required {bond_amount}")
435
433
  return False
436
434
 
437
435
  protocol_contracts = OLAS_CONTRACTS.get(self.chain_name.lower(), {})
@@ -682,7 +680,9 @@ class LifecycleManagerMixin:
682
680
  )
683
681
  return True
684
682
 
685
- logger.info(f"[REGISTER] Service Owner approving Token Utility for bond: {bond_amount_wei} wei")
683
+ logger.info(
684
+ f"[REGISTER] Service Owner approving Token Utility for bond: {bond_amount_wei} wei"
685
+ )
686
686
 
687
687
  utility_address = str(
688
688
  OLAS_CONTRACTS[self.chain_name]["OLAS_SERVICE_REGISTRY_TOKEN_UTILITY"]
@@ -697,9 +697,7 @@ class LifecycleManagerMixin:
697
697
  )
698
698
 
699
699
  if allowance >= bond_amount_wei:
700
- logger.debug(
701
- f"[REGISTER] Sufficient allowance ({allowance} >= {bond_amount_wei})"
702
- )
700
+ logger.debug(f"[REGISTER] Sufficient allowance ({allowance} >= {bond_amount_wei})")
703
701
  return True
704
702
 
705
703
  # Use service owner which holds the OLAS tokens (not necessarily master)
@@ -800,7 +798,9 @@ class LifecycleManagerMixin:
800
798
  )
801
799
  return False
802
800
 
803
- logger.debug(f"[DEPLOY] Preparing deploy tx for owner {self._get_label(self.service.service_owner_address)}")
801
+ logger.debug(
802
+ f"[DEPLOY] Preparing deploy tx for owner {self._get_label(self.service.service_owner_address)}"
803
+ )
804
804
  deploy_tx = self.manager.prepare_deploy_tx(
805
805
  from_address=self.service.service_owner_address,
806
806
  service_id=self.service.service_id,
@@ -855,7 +855,7 @@ class LifecycleManagerMixin:
855
855
  _, agent_instances = self.registry.call("getAgentInstances", self.service.service_id)
856
856
  service_info = self.registry.get_service(self.service.service_id)
857
857
  threshold = service_info["threshold"]
858
- # Store the multisig in the wallet with tag
858
+ # Store the multisig in the wallet with tag
859
859
  multisig_tag = f"{self.service.service_name}_multisig"
860
860
 
861
861
  # ARCHIVING LOGIC: If tag is already taken by a different address, rename the old one
@@ -90,6 +90,7 @@ class StakingManagerMixin:
90
90
  # Try token/contract names
91
91
  try:
92
92
  from iwa.core.chain import ChainInterfaces
93
+
93
94
  chain_interface = ChainInterfaces().get(self.chain_name)
94
95
  token_name = chain_interface.chain.get_token_name(address)
95
96
  if token_name:
@@ -407,7 +408,9 @@ class StakingManagerMixin:
407
408
  # NOTE: We don't check OLAS balance here because OLAS was already
408
409
  # deposited to the Token Utility during activation (min_staking_deposit)
409
410
  # and registration (agent_bond). The staking contract pulls from there.
410
- logger.debug("[STAKE] OLAS already deposited to Token Utility during activation/registration")
411
+ logger.debug(
412
+ "[STAKE] OLAS already deposited to Token Utility during activation/registration"
413
+ )
411
414
 
412
415
  return {"min_deposit": min_deposit, "staking_token": staking_token}
413
416
 
@@ -437,7 +440,9 @@ class StakingManagerMixin:
437
440
  owner_address = self.service.service_owner_address or self.wallet.master_account.address
438
441
 
439
442
  # Approve service NFT - this is an ERC-721 approval, not ERC-20
440
- logger.debug(f"[STAKE] Approving service NFT for staking contract from {self._get_label(owner_address)}...")
443
+ logger.debug(
444
+ f"[STAKE] Approving service NFT for staking contract from {self._get_label(owner_address)}..."
445
+ )
441
446
  approve_tx = self.registry.prepare_approve_tx(
442
447
  from_address=owner_address,
443
448
  spender=staking_contract.address,
@@ -483,7 +488,9 @@ class StakingManagerMixin:
483
488
  # Use service owner which holds the NFT (not necessarily master)
484
489
  owner_address = self.service.service_owner_address or self.wallet.master_account.address
485
490
 
486
- logger.debug(f"[STAKE] Preparing stake transaction from {self._get_label(owner_address)}...")
491
+ logger.debug(
492
+ f"[STAKE] Preparing stake transaction from {self._get_label(owner_address)}..."
493
+ )
487
494
  stake_tx = staking_contract.prepare_stake_tx(
488
495
  from_address=owner_address,
489
496
  service_id=self.service.service_id,
@@ -601,9 +608,7 @@ class StakingManagerMixin:
601
608
  return False
602
609
 
603
610
  tx_hash = get_tx_hash(receipt)
604
- logger.info(
605
- f"Unstake transaction sent: {tx_hash if receipt else 'No Receipt'}"
606
- )
611
+ logger.info(f"Unstake transaction sent: {tx_hash if receipt else 'No Receipt'}")
607
612
 
608
613
  events = staking_contract.extract_events(receipt)
609
614
 
@@ -20,10 +20,12 @@ class TestOlasArchiving(unittest.TestCase):
20
20
  self.mock_wallet.key_storage = self.mock_key_storage
21
21
 
22
22
  # Initialize ServiceManager
23
- with patch("iwa.core.models.Config"), \
24
- patch("iwa.plugins.olas.service_manager.base.ChainInterfaces"), \
25
- patch("iwa.plugins.olas.service_manager.base.ContractCache"), \
26
- patch("iwa.plugins.olas.service_manager.base.ServiceRegistryContract"):
23
+ with (
24
+ patch("iwa.core.models.Config"),
25
+ patch("iwa.plugins.olas.service_manager.base.ChainInterfaces"),
26
+ patch("iwa.plugins.olas.service_manager.base.ContractCache"),
27
+ patch("iwa.plugins.olas.service_manager.base.ServiceRegistryContract"),
28
+ ):
27
29
  self.sm = ServiceManager(self.mock_wallet)
28
30
  self.sm.service = Service(service_name="trader_psi", chain_name="gnosis", service_id=1)
29
31
  self.sm.chain_name = "gnosis"
@@ -40,23 +42,30 @@ class TestOlasArchiving(unittest.TestCase):
40
42
 
41
43
  # 2. Mock required contract calls for deploy()
42
44
  self.sm.registry.get_service.return_value = {
43
- "state": ServiceState.FINISHED_REGISTRATION, # DEPLOYED
45
+ "state": ServiceState.FINISHED_REGISTRATION, # DEPLOYED
44
46
  "security_deposit": 0,
45
47
  "multisig": new_address,
46
48
  "threshold": 1,
47
- "configHash": b"\x00" * 32
49
+ "configHash": b"\x00" * 32,
48
50
  }
49
- self.sm.registry.call.return_value = (None, []) # getAgentInstances
51
+ self.sm.registry.call.return_value = (None, []) # getAgentInstances
50
52
 
51
53
  # 3. Trigger deploy (archiving happens here)
52
- with patch.object(self.mock_wallet, "sign_and_send_transaction", return_value=(True, {"status": 1})), \
53
- patch.object(self.sm.registry, "extract_events", return_value=[
54
- {"name": "DeployService", "args": {}},
55
- {"name": "CreateMultisigWithAgents", "args": {"multisig": new_address}}
56
- ]), \
57
- patch("iwa.plugins.olas.service_manager.lifecycle.get_tx_hash", return_value="0xhash"), \
58
- patch("iwa.core.models.StoredSafeAccount") as mock_safe_cls:
59
-
54
+ with (
55
+ patch.object(
56
+ self.mock_wallet, "sign_and_send_transaction", return_value=(True, {"status": 1})
57
+ ),
58
+ patch.object(
59
+ self.sm.registry,
60
+ "extract_events",
61
+ return_value=[
62
+ {"name": "DeployService", "args": {}},
63
+ {"name": "CreateMultisigWithAgents", "args": {"multisig": new_address}},
64
+ ],
65
+ ),
66
+ patch("iwa.plugins.olas.service_manager.lifecycle.get_tx_hash", return_value="0xhash"),
67
+ patch("iwa.core.models.StoredSafeAccount") as mock_safe_cls,
68
+ ):
60
69
  self.sm.deploy(fund_multisig=False)
61
70
 
62
71
  # 4. Verify rename_account was called for the old address
@@ -69,5 +78,6 @@ class TestOlasArchiving(unittest.TestCase):
69
78
  self.assertEqual(kwargs["address"], new_address)
70
79
  self.assertEqual(kwargs["tag"], multisig_tag)
71
80
 
81
+
72
82
  if __name__ == "__main__":
73
83
  unittest.main()
@@ -309,9 +309,11 @@ def test_importer_import_service_config_duplicate(mock_wallet):
309
309
 
310
310
  def test_sm_create_token_utility_missing(mock_wallet):
311
311
  """Cover create() with missing token utility (lines 204-206)."""
312
- with patch("iwa.core.models.Config"), \
313
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
314
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
312
+ with (
313
+ patch("iwa.core.models.Config"),
314
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
315
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
316
+ ):
315
317
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
316
318
  sm = ServiceManager(mock_wallet)
317
319
 
@@ -323,9 +325,11 @@ def test_sm_create_token_utility_missing(mock_wallet):
323
325
 
324
326
  def test_sm_get_staking_status_staked_info_fail(mock_wallet):
325
327
  """Cover get_staking_status with STAKED but get_service_info fails (lines 843-854)."""
326
- with patch("iwa.core.models.Config"), \
327
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
328
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
328
+ with (
329
+ patch("iwa.core.models.Config"),
330
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
331
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
332
+ ):
329
333
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
330
334
  sm = ServiceManager(mock_wallet)
331
335
  sm.service = Service(
@@ -347,9 +351,11 @@ def test_sm_get_staking_status_staked_info_fail(mock_wallet):
347
351
 
348
352
  def test_sm_call_checkpoint_prepare_fail(mock_wallet):
349
353
  """Cover call_checkpoint prepare failure (lines 1100-1102)."""
350
- with patch("iwa.core.models.Config"), \
351
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
352
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
354
+ with (
355
+ patch("iwa.core.models.Config"),
356
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
357
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
358
+ ):
353
359
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
354
360
  sm = ServiceManager(mock_wallet)
355
361
  sm.service = Service(
@@ -369,9 +375,11 @@ def test_sm_call_checkpoint_prepare_fail(mock_wallet):
369
375
 
370
376
  def test_sm_spin_up_no_service(mock_wallet):
371
377
  """Cover spin_up with no service (lines 1167-1170)."""
372
- with patch("iwa.core.models.Config"), \
373
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
374
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
378
+ with (
379
+ patch("iwa.core.models.Config"),
380
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
381
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
382
+ ):
375
383
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
376
384
  sm = ServiceManager(mock_wallet)
377
385
  sm.service = None
@@ -382,9 +390,11 @@ def test_sm_spin_up_no_service(mock_wallet):
382
390
 
383
391
  def test_sm_spin_up_activation_fail(mock_wallet):
384
392
  """Cover spin_up activation failure (lines 1181-1183)."""
385
- with patch("iwa.core.models.Config"), \
386
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
387
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
393
+ with (
394
+ patch("iwa.core.models.Config"),
395
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
396
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
397
+ ):
388
398
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
389
399
  sm = ServiceManager(mock_wallet)
390
400
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
@@ -402,9 +412,11 @@ def test_sm_spin_up_activation_fail(mock_wallet):
402
412
 
403
413
  def test_sm_wind_down_no_service(mock_wallet):
404
414
  """Cover wind_down with no service (lines 1264-1266)."""
405
- with patch("iwa.core.models.Config"), \
406
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
407
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
415
+ with (
416
+ patch("iwa.core.models.Config"),
417
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
418
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
419
+ ):
408
420
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
409
421
  sm = ServiceManager(mock_wallet)
410
422
  sm.service = None
@@ -415,9 +427,11 @@ def test_sm_wind_down_no_service(mock_wallet):
415
427
 
416
428
  def test_sm_wind_down_nonexistent(mock_wallet):
417
429
  """Cover wind_down with non-existent service (lines 1274-1276)."""
418
- with patch("iwa.core.models.Config"), \
419
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
420
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
430
+ with (
431
+ patch("iwa.core.models.Config"),
432
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
433
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
434
+ ):
421
435
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
422
436
  sm = ServiceManager(mock_wallet)
423
437
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
@@ -432,9 +446,11 @@ def test_sm_wind_down_nonexistent(mock_wallet):
432
446
 
433
447
  def test_sm_mech_request_no_service(mock_wallet):
434
448
  """Cover _send_legacy_mech_request with no service (lines 1502-1504)."""
435
- with patch("iwa.core.models.Config"), \
436
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
437
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
449
+ with (
450
+ patch("iwa.core.models.Config"),
451
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
452
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
453
+ ):
438
454
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
439
455
  sm = ServiceManager(mock_wallet)
440
456
  sm.service = None
@@ -445,9 +461,11 @@ def test_sm_mech_request_no_service(mock_wallet):
445
461
 
446
462
  def test_sm_mech_request_no_address(mock_wallet):
447
463
  """Cover _send_legacy_mech_request missing mech address (lines 1510-1512)."""
448
- with patch("iwa.core.models.Config"), \
449
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
450
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
464
+ with (
465
+ patch("iwa.core.models.Config"),
466
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
467
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
468
+ ):
451
469
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
452
470
  sm = ServiceManager(mock_wallet)
453
471
  sm.service = Service(service_name="t", chain_name="unknown", service_id=1)
@@ -458,8 +476,10 @@ def test_sm_mech_request_no_address(mock_wallet):
458
476
 
459
477
  def test_sm_marketplace_mech_no_service(mock_wallet):
460
478
  """Cover _send_marketplace_mech_request with no service (lines 1549-1551)."""
461
- with patch("iwa.core.models.Config"), \
462
- patch("iwa.plugins.olas.service_manager.base.ContractCache"):
479
+ with (
480
+ patch("iwa.core.models.Config"),
481
+ patch("iwa.plugins.olas.service_manager.base.ContractCache"),
482
+ ):
463
483
  sm = ServiceManager(mock_wallet)
464
484
  sm.service = None
465
485
 
@@ -104,8 +104,6 @@ def mock_chain_interfaces():
104
104
  yield mock
105
105
 
106
106
 
107
-
108
-
109
107
  @pytest.fixture
110
108
  def service_manager(
111
109
  mock_config,
@@ -113,13 +111,14 @@ def service_manager(
113
111
  mock_registry,
114
112
  mock_manager_contract,
115
113
  mock_chain_interfaces,
116
-
117
114
  mock_olas_config,
118
115
  mock_service,
119
116
  ):
120
117
  """ServiceManager fixture with mocked dependencies."""
121
- with patch("iwa.plugins.olas.service_manager.base.Config") as local_mock_config, \
122
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache:
118
+ with (
119
+ patch("iwa.plugins.olas.service_manager.base.Config") as local_mock_config,
120
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
121
+ ):
123
122
  instance = local_mock_config.return_value
124
123
  instance.plugins = {"olas": mock_olas_config}
125
124
  instance.save_config = MagicMock()
@@ -136,7 +135,6 @@ def service_manager(
136
135
  yield sm
137
136
 
138
137
 
139
-
140
138
  def test_init(service_manager):
141
139
  """Test initialization."""
142
140
  assert service_manager.registry is not None
@@ -179,9 +177,7 @@ def test_create_no_event(service_manager, mock_wallet):
179
177
  mock_wallet.sign_and_send_transaction.return_value = (True, {})
180
178
  service_manager.registry.extract_events.return_value = []
181
179
 
182
- res = service_manager.create(
183
- token_address_or_tag="0x1111111111111111111111111111111111111111"
184
- )
180
+ res = service_manager.create(token_address_or_tag="0x1111111111111111111111111111111111111111")
185
181
  # create() finds no ID, logs error, returns None for service_id.
186
182
  assert res is None
187
183
 
@@ -911,7 +907,9 @@ def test_activate_registration_token_service_sends_security_deposit_as_value(
911
907
 
912
908
  # Mock balance check to pass
913
909
  mock_wallet.balance_service = MagicMock()
914
- mock_wallet.balance_service.get_erc20_balance_wei.return_value = 100 * 10**18 # Plenty of balance
910
+ mock_wallet.balance_service.get_erc20_balance_wei.return_value = (
911
+ 100 * 10**18
912
+ ) # Plenty of balance
915
913
 
916
914
  # Mock allowance to pass check (return an int)
917
915
  mock_wallet.transfer_service.get_erc20_allowance.return_value = 10**20 # Plenty of allowance
@@ -26,10 +26,11 @@ def mock_wallet():
26
26
  @pytest.fixture
27
27
  def mock_manager(mock_wallet):
28
28
  """Setup a ServiceManager with mocked dependencies."""
29
- with patch("iwa.plugins.olas.service_manager.base.Config") as mock_cfg_cls, \
30
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
31
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
32
-
29
+ with (
30
+ patch("iwa.plugins.olas.service_manager.base.Config") as mock_cfg_cls,
31
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
32
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
33
+ ):
33
34
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
34
35
 
35
36
  mock_cfg = mock_cfg_cls.return_value
@@ -237,7 +237,9 @@ def test_activate_registration(
237
237
  @patch("iwa.plugins.olas.service_manager.base.ServiceRegistryContract")
238
238
  @patch("iwa.plugins.olas.service_manager.base.ServiceManagerContract")
239
239
  @patch("iwa.plugins.olas.service_manager.base.ContractCache")
240
- def test_register_agent(mock_cache, mock_sm_contract, mock_registry_contract, mock_config_cls, mock_wallet):
240
+ def test_register_agent(
241
+ mock_cache, mock_sm_contract, mock_registry_contract, mock_config_cls, mock_wallet
242
+ ):
241
243
  """Test agent registration flow."""
242
244
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
243
245
  mock_config_inst = mock_config_cls.return_value
@@ -354,7 +356,9 @@ def test_deploy(mock_cache, mock_sm_contract, mock_registry_contract, mock_confi
354
356
  @patch("iwa.plugins.olas.service_manager.base.ServiceRegistryContract")
355
357
  @patch("iwa.plugins.olas.service_manager.base.ServiceManagerContract")
356
358
  @patch("iwa.plugins.olas.service_manager.base.ContractCache")
357
- def test_terminate(mock_cache, mock_sm_contract, mock_registry_contract, mock_config_cls, mock_wallet):
359
+ def test_terminate(
360
+ mock_cache, mock_sm_contract, mock_registry_contract, mock_config_cls, mock_wallet
361
+ ):
358
362
  """Test service termination."""
359
363
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
360
364
  # Setup mock service
@@ -457,7 +461,6 @@ def test_stake(mock_cache, mock_sm_contract, mock_registry_contract, mock_config
457
461
  "required_agent_bond": 50000000000000000000,
458
462
  }
459
463
 
460
-
461
464
  success = manager.stake(mock_staking)
462
465
  assert success is True
463
466
  assert manager.service.staking_contract_address == "0xDDdDddDdDdddDDddDDddDDDDdDdDDdDDdDDDDDDd"
@@ -480,8 +483,6 @@ def test_stake(mock_cache, mock_sm_contract, mock_registry_contract, mock_config
480
483
  assert manager.stake(mock_staking) is False
481
484
  mock_staking.get_service_ids.return_value = []
482
485
 
483
-
484
-
485
486
  # 4. Approve fail
486
487
  mock_wallet.sign_and_send_transaction.return_value = (False, {})
487
488
  assert manager.stake(mock_staking) is False
@@ -33,9 +33,11 @@ def mock_wallet():
33
33
 
34
34
  def test_sm_unstake_not_staked(mock_wallet):
35
35
  """Cover unstake when not staked (lines 736-738)."""
36
- with patch("iwa.core.models.Config"), \
37
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
38
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
36
+ with (
37
+ patch("iwa.core.models.Config"),
38
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
39
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
40
+ ):
39
41
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
40
42
  sm = ServiceManager(mock_wallet)
41
43
  sm.service = Service(
@@ -51,9 +53,11 @@ def test_sm_unstake_not_staked(mock_wallet):
51
53
 
52
54
  def test_sm_unstake_tx_fails(mock_wallet):
53
55
  """Cover unstake transaction failure (lines 766-768)."""
54
- with patch("iwa.core.models.Config"), \
55
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
56
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
56
+ with (
57
+ patch("iwa.core.models.Config"),
58
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
59
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
60
+ ):
57
61
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
58
62
  sm = ServiceManager(mock_wallet)
59
63
  sm.service = Service(
@@ -77,9 +81,11 @@ def test_sm_unstake_tx_fails(mock_wallet):
77
81
 
78
82
  def test_sm_get_staking_status_no_staking_address(mock_wallet):
79
83
  """Cover get_staking_status with no staking address (lines 831)."""
80
- with patch("iwa.core.models.Config"), \
81
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
82
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
84
+ with (
85
+ patch("iwa.core.models.Config"),
86
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
87
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
88
+ ):
83
89
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
84
90
  sm = ServiceManager(mock_wallet)
85
91
  sm.service = Service(
@@ -97,9 +103,11 @@ def test_sm_get_staking_status_no_staking_address(mock_wallet):
97
103
 
98
104
  def test_sm_get_staking_status_with_full_info(mock_wallet):
99
105
  """Cover get_staking_status with complete info (lines 866-891)."""
100
- with patch("iwa.core.models.Config"), \
101
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
102
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
106
+ with (
107
+ patch("iwa.core.models.Config"),
108
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
109
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
110
+ ):
103
111
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
104
112
  sm = ServiceManager(mock_wallet)
105
113
  sm.service = Service(
@@ -142,9 +150,11 @@ def test_sm_get_staking_status_with_full_info(mock_wallet):
142
150
 
143
151
  def test_sm_claim_rewards_no_service(mock_wallet):
144
152
  """Cover claim_rewards with no service (lines 936-938)."""
145
- with patch("iwa.core.models.Config"), \
146
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
147
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
153
+ with (
154
+ patch("iwa.core.models.Config"),
155
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
156
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
157
+ ):
148
158
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
149
159
  sm = ServiceManager(mock_wallet)
150
160
  sm.service = None
@@ -156,9 +166,11 @@ def test_sm_claim_rewards_no_service(mock_wallet):
156
166
 
157
167
  def test_sm_claim_rewards_no_staking_address(mock_wallet):
158
168
  """Cover claim_rewards with no staking address (lines 939-943)."""
159
- with patch("iwa.core.models.Config"), \
160
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
161
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
169
+ with (
170
+ patch("iwa.core.models.Config"),
171
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
172
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
173
+ ):
162
174
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
163
175
  sm = ServiceManager(mock_wallet)
164
176
  sm.service = Service(
@@ -171,9 +183,11 @@ def test_sm_claim_rewards_no_staking_address(mock_wallet):
171
183
 
172
184
  def test_sm_claim_rewards_tx_fails(mock_wallet):
173
185
  """Cover claim_rewards transaction failure (lines 967-968)."""
174
- with patch("iwa.core.models.Config"), \
175
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
176
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
186
+ with (
187
+ patch("iwa.core.models.Config"),
188
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
189
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
190
+ ):
177
191
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
178
192
  sm = ServiceManager(mock_wallet)
179
193
  sm.service = Service(
@@ -199,9 +213,11 @@ def test_sm_claim_rewards_tx_fails(mock_wallet):
199
213
 
200
214
  mock_wallet.sign_and_send_transaction.return_value = (False, None)
201
215
 
202
- with patch("iwa.plugins.olas.service_manager.drain.StakingContract", return_value=mock_staking):
203
- success, amount = sm.claim_rewards()
204
- assert success is False
216
+ with patch(
217
+ "iwa.plugins.olas.service_manager.drain.StakingContract", return_value=mock_staking
218
+ ):
219
+ success, amount = sm.claim_rewards()
220
+ assert success is False
205
221
 
206
222
 
207
223
  # === SERVICE MANAGER SPIN_UP STATE TRANSITIONS (lines 1188-1241) ===
@@ -209,9 +225,11 @@ def test_sm_claim_rewards_tx_fails(mock_wallet):
209
225
 
210
226
  def test_sm_spin_up_state_mismatch_after_activation(mock_wallet):
211
227
  """Cover spin_up state mismatch after activation (lines 1188-1191)."""
212
- with patch("iwa.core.models.Config"), \
213
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
214
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
228
+ with (
229
+ patch("iwa.core.models.Config"),
230
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
231
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
232
+ ):
215
233
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
216
234
  sm = ServiceManager(mock_wallet)
217
235
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
@@ -233,9 +251,11 @@ def test_sm_spin_up_state_mismatch_after_activation(mock_wallet):
233
251
 
234
252
  def test_sm_spin_up_registration_fails(mock_wallet):
235
253
  """Cover spin_up registration failure (lines 1199-1201)."""
236
- with patch("iwa.core.models.Config"), \
237
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
238
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
254
+ with (
255
+ patch("iwa.core.models.Config"),
256
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
257
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
258
+ ):
239
259
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
240
260
  sm = ServiceManager(mock_wallet)
241
261
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
@@ -253,9 +273,11 @@ def test_sm_spin_up_registration_fails(mock_wallet):
253
273
 
254
274
  def test_sm_spin_up_deploy_fails(mock_wallet):
255
275
  """Cover spin_up deploy failure (lines 1216-1218)."""
256
- with patch("iwa.core.models.Config"), \
257
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
258
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
276
+ with (
277
+ patch("iwa.core.models.Config"),
278
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
279
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
280
+ ):
259
281
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
260
282
  sm = ServiceManager(mock_wallet)
261
283
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
@@ -273,9 +295,11 @@ def test_sm_spin_up_deploy_fails(mock_wallet):
273
295
 
274
296
  def test_sm_wind_down_terminate_fails(mock_wallet):
275
297
  """Cover wind_down terminate failure (lines 1299-1301)."""
276
- with patch("iwa.core.models.Config"), \
277
- patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache, \
278
- patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache):
298
+ with (
299
+ patch("iwa.core.models.Config"),
300
+ patch("iwa.plugins.olas.service_manager.base.ContractCache") as mock_cache,
301
+ patch("iwa.plugins.olas.service_manager.staking.ContractCache", mock_cache),
302
+ ):
279
303
  mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
280
304
  sm = ServiceManager(mock_wallet)
281
305
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
@@ -293,8 +317,10 @@ def test_sm_wind_down_terminate_fails(mock_wallet):
293
317
 
294
318
  def test_sm_wind_down_unbond_fails(mock_wallet):
295
319
  """Cover wind_down unbond failure (lines 1315-1317)."""
296
- with patch("iwa.core.models.Config"), \
297
- patch("iwa.plugins.olas.service_manager.base.ContractCache"):
320
+ with (
321
+ patch("iwa.core.models.Config"),
322
+ patch("iwa.plugins.olas.service_manager.base.ContractCache"),
323
+ ):
298
324
  sm = ServiceManager(mock_wallet)
299
325
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
300
326
 
@@ -1,5 +1,5 @@
1
-
2
1
  """Tool to drain specific accounts to a master address."""
2
+
3
3
  import argparse
4
4
  import sys
5
5
  from pathlib import Path
@@ -56,5 +56,6 @@ def main() -> None:
56
56
  except Exception:
57
57
  logger.exception(f"Error draining {tag}")
58
58
 
59
+
59
60
  if __name__ == "__main__":
60
61
  main()