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.
- iwa/core/chain/interface.py +32 -21
- iwa/core/chain/rate_limiter.py +0 -6
- iwa/core/chainlist.py +15 -10
- iwa/core/cli.py +3 -0
- iwa/core/contracts/cache.py +1 -1
- iwa/core/contracts/contract.py +1 -0
- iwa/core/contracts/decoder.py +10 -4
- iwa/core/http.py +31 -0
- iwa/core/ipfs.py +11 -19
- iwa/core/keys.py +10 -4
- iwa/core/models.py +1 -3
- iwa/core/pricing.py +3 -21
- iwa/core/rpc_monitor.py +1 -0
- iwa/core/services/balance.py +0 -1
- iwa/core/services/safe.py +8 -2
- iwa/core/services/safe_executor.py +52 -18
- iwa/core/services/transaction.py +32 -12
- iwa/core/services/transfer/erc20.py +0 -1
- iwa/core/services/transfer/native.py +1 -1
- iwa/core/tests/test_gnosis_fee.py +6 -2
- iwa/core/tests/test_ipfs.py +1 -1
- iwa/core/tests/test_regression_fixes.py +3 -6
- iwa/core/utils.py +2 -0
- iwa/core/wallet.py +3 -1
- iwa/plugins/olas/constants.py +15 -5
- iwa/plugins/olas/contracts/activity_checker.py +3 -3
- iwa/plugins/olas/contracts/staking.py +0 -1
- iwa/plugins/olas/events.py +15 -13
- iwa/plugins/olas/importer.py +26 -20
- iwa/plugins/olas/plugin.py +16 -14
- iwa/plugins/olas/service_manager/drain.py +1 -3
- iwa/plugins/olas/service_manager/lifecycle.py +9 -9
- iwa/plugins/olas/service_manager/staking.py +11 -6
- iwa/plugins/olas/tests/test_olas_archiving.py +25 -15
- iwa/plugins/olas/tests/test_olas_integration.py +49 -29
- iwa/plugins/olas/tests/test_service_manager.py +8 -10
- iwa/plugins/olas/tests/test_service_manager_errors.py +5 -4
- iwa/plugins/olas/tests/test_service_manager_flows.py +6 -5
- iwa/plugins/olas/tests/test_service_staking.py +64 -38
- iwa/tools/drain_accounts.py +2 -1
- iwa/tools/reset_env.py +2 -1
- iwa/tools/test_chainlist.py +5 -1
- iwa/tui/screens/wallets.py +1 -3
- iwa/web/routers/olas/services.py +10 -5
- {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/METADATA +1 -1
- {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/RECORD +58 -57
- tests/test_balance_service.py +0 -2
- tests/test_chain.py +1 -2
- tests/test_rate_limiter_retry.py +2 -7
- tests/test_rpc_efficiency.py +4 -1
- tests/test_rpc_rate_limit.py +1 -0
- tests/test_rpc_rotation.py +4 -4
- tests/test_safe_executor.py +76 -50
- tests/test_safe_integration.py +11 -6
- {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/WHEEL +0 -0
- {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/entry_points.txt +0 -0
- {iwa-0.0.58.dist-info → iwa-0.0.59.dist-info}/licenses/LICENSE +0 -0
- {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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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,
|
|
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, [])
|
|
51
|
+
self.sm.registry.call.return_value = (None, []) # getAgentInstances
|
|
50
52
|
|
|
51
53
|
# 3. Trigger deploy (archiving happens here)
|
|
52
|
-
with
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
313
|
-
|
|
314
|
-
|
|
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
|
|
327
|
-
|
|
328
|
-
|
|
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
|
|
351
|
-
|
|
352
|
-
|
|
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
|
|
373
|
-
|
|
374
|
-
|
|
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
|
|
386
|
-
|
|
387
|
-
|
|
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
|
|
406
|
-
|
|
407
|
-
|
|
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
|
|
419
|
-
|
|
420
|
-
|
|
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
|
|
436
|
-
|
|
437
|
-
|
|
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
|
|
449
|
-
|
|
450
|
-
|
|
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
|
|
462
|
-
|
|
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
|
|
122
|
-
|
|
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 =
|
|
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
|
|
30
|
-
|
|
31
|
-
|
|
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(
|
|
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(
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
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
|
|
55
|
-
|
|
56
|
-
|
|
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
|
|
81
|
-
|
|
82
|
-
|
|
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
|
|
101
|
-
|
|
102
|
-
|
|
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
|
|
146
|
-
|
|
147
|
-
|
|
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
|
|
160
|
-
|
|
161
|
-
|
|
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
|
|
175
|
-
|
|
176
|
-
|
|
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(
|
|
203
|
-
|
|
204
|
-
|
|
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
|
|
213
|
-
|
|
214
|
-
|
|
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
|
|
237
|
-
|
|
238
|
-
|
|
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
|
|
257
|
-
|
|
258
|
-
|
|
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
|
|
277
|
-
|
|
278
|
-
|
|
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
|
|
297
|
-
|
|
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
|
|
iwa/tools/drain_accounts.py
CHANGED
|
@@ -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()
|