iwa 0.0.19__py3-none-any.whl → 0.0.20__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.
@@ -33,7 +33,10 @@ 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"):
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):
39
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
37
40
  sm = ServiceManager(mock_wallet)
38
41
  sm.service = Service(
39
42
  service_name="t", chain_name="gnosis", service_id=1, multisig_address=VALID_ADDR
@@ -48,7 +51,10 @@ def test_sm_unstake_not_staked(mock_wallet):
48
51
 
49
52
  def test_sm_unstake_tx_fails(mock_wallet):
50
53
  """Cover unstake transaction failure (lines 766-768)."""
51
- with patch("iwa.core.models.Config"):
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):
57
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
52
58
  sm = ServiceManager(mock_wallet)
53
59
  sm.service = Service(
54
60
  service_name="t", chain_name="gnosis", service_id=1, multisig_address=VALID_ADDR
@@ -71,7 +77,10 @@ def test_sm_unstake_tx_fails(mock_wallet):
71
77
 
72
78
  def test_sm_get_staking_status_no_staking_address(mock_wallet):
73
79
  """Cover get_staking_status with no staking address (lines 831)."""
74
- with patch("iwa.core.models.Config"):
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):
83
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
75
84
  sm = ServiceManager(mock_wallet)
76
85
  sm.service = Service(
77
86
  service_name="t", chain_name="gnosis", service_id=1, staking_contract_address=VALID_ADDR
@@ -88,7 +97,10 @@ def test_sm_get_staking_status_no_staking_address(mock_wallet):
88
97
 
89
98
  def test_sm_get_staking_status_with_full_info(mock_wallet):
90
99
  """Cover get_staking_status with complete info (lines 866-891)."""
91
- with patch("iwa.core.models.Config"):
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):
103
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
92
104
  sm = ServiceManager(mock_wallet)
93
105
  sm.service = Service(
94
106
  service_name="t", chain_name="gnosis", service_id=1, staking_contract_address=VALID_ADDR
@@ -130,7 +142,10 @@ def test_sm_get_staking_status_with_full_info(mock_wallet):
130
142
 
131
143
  def test_sm_claim_rewards_no_service(mock_wallet):
132
144
  """Cover claim_rewards with no service (lines 936-938)."""
133
- with patch("iwa.core.models.Config"):
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):
148
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
134
149
  sm = ServiceManager(mock_wallet)
135
150
  sm.service = None
136
151
 
@@ -141,7 +156,10 @@ def test_sm_claim_rewards_no_service(mock_wallet):
141
156
 
142
157
  def test_sm_claim_rewards_no_staking_address(mock_wallet):
143
158
  """Cover claim_rewards with no staking address (lines 939-943)."""
144
- with patch("iwa.core.models.Config"):
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):
162
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
145
163
  sm = ServiceManager(mock_wallet)
146
164
  sm.service = Service(
147
165
  service_name="t", chain_name="gnosis", service_id=1, staking_contract_address=None
@@ -153,7 +171,10 @@ def test_sm_claim_rewards_no_staking_address(mock_wallet):
153
171
 
154
172
  def test_sm_claim_rewards_tx_fails(mock_wallet):
155
173
  """Cover claim_rewards transaction failure (lines 967-968)."""
156
- with patch("iwa.core.models.Config"):
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):
177
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
157
178
  sm = ServiceManager(mock_wallet)
158
179
  sm.service = Service(
159
180
  service_name="t",
@@ -165,12 +186,22 @@ def test_sm_claim_rewards_tx_fails(mock_wallet):
165
186
 
166
187
  mock_staking = MagicMock()
167
188
  mock_staking.prepare_claim_tx.return_value = {"to": VALID_ADDR}
189
+ mock_staking.get_staking_state.return_value = StakingState.STAKED
190
+ mock_staking.get_accrued_rewards.return_value = 100
191
+
192
+ def get_contract_side_effect(cls, *args, **kwargs):
193
+ print(f"DEBUG: get_contract called with {cls!r}")
194
+ if "StakingContract" in str(cls):
195
+ return mock_staking
196
+ return cls(*args, **kwargs)
197
+
198
+ mock_cache.return_value.get_contract.side_effect = get_contract_side_effect
168
199
 
169
200
  mock_wallet.sign_and_send_transaction.return_value = (False, None)
170
201
 
171
- with patch("iwa.plugins.olas.service_manager.StakingContract", return_value=mock_staking):
172
- success, amount = sm.claim_rewards()
173
- assert success is False
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
174
205
 
175
206
 
176
207
  # === SERVICE MANAGER SPIN_UP STATE TRANSITIONS (lines 1188-1241) ===
@@ -178,7 +209,10 @@ def test_sm_claim_rewards_tx_fails(mock_wallet):
178
209
 
179
210
  def test_sm_spin_up_state_mismatch_after_activation(mock_wallet):
180
211
  """Cover spin_up state mismatch after activation (lines 1188-1191)."""
181
- with patch("iwa.core.models.Config"):
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):
215
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
182
216
  sm = ServiceManager(mock_wallet)
183
217
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
184
218
 
@@ -199,7 +233,10 @@ def test_sm_spin_up_state_mismatch_after_activation(mock_wallet):
199
233
 
200
234
  def test_sm_spin_up_registration_fails(mock_wallet):
201
235
  """Cover spin_up registration failure (lines 1199-1201)."""
202
- with patch("iwa.core.models.Config"):
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):
239
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
203
240
  sm = ServiceManager(mock_wallet)
204
241
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
205
242
 
@@ -216,7 +253,10 @@ def test_sm_spin_up_registration_fails(mock_wallet):
216
253
 
217
254
  def test_sm_spin_up_deploy_fails(mock_wallet):
218
255
  """Cover spin_up deploy failure (lines 1216-1218)."""
219
- with patch("iwa.core.models.Config"):
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):
259
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
220
260
  sm = ServiceManager(mock_wallet)
221
261
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
222
262
 
@@ -233,7 +273,10 @@ def test_sm_spin_up_deploy_fails(mock_wallet):
233
273
 
234
274
  def test_sm_wind_down_terminate_fails(mock_wallet):
235
275
  """Cover wind_down terminate failure (lines 1299-1301)."""
236
- with patch("iwa.core.models.Config"):
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):
279
+ mock_cache.return_value.get_contract.side_effect = lambda cls, *a, **k: cls(*a, **k)
237
280
  sm = ServiceManager(mock_wallet)
238
281
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
239
282
 
@@ -250,7 +293,8 @@ def test_sm_wind_down_terminate_fails(mock_wallet):
250
293
 
251
294
  def test_sm_wind_down_unbond_fails(mock_wallet):
252
295
  """Cover wind_down unbond failure (lines 1315-1317)."""
253
- with patch("iwa.core.models.Config"):
296
+ with patch("iwa.core.models.Config"), \
297
+ patch("iwa.plugins.olas.service_manager.base.ContractCache"):
254
298
  sm = ServiceManager(mock_wallet)
255
299
  sm.service = Service(service_name="t", chain_name="gnosis", service_id=1)
256
300
 
@@ -25,19 +25,12 @@ def mock_staking():
25
25
  def test_staking_get_service_info_nested_tuple(mock_staking):
26
26
  """Test get_service_info with nested tuple result from web3."""
27
27
  nested_result = (("0xMultisig", "0xOwner", (1, 2), 1000, 500, 0),)
28
- mock_staking.call.side_effect = [
29
- "0x1", # activityChecker
30
- 100, # availableRewards
31
- 200, # balance
32
- 3600, # livenessPeriod
33
- 10, # rewardsPerSecond
34
- 10, # maxNumServices
35
- 50, # minStakingDeposit
36
- 7200, # minStakingDuration
37
- "0xToken", # stakingToken
38
- nested_result, # getServiceInfo
39
- 2000, # getNextRewardCheckpointTimestamp
40
- ]
28
+ mock_staking.call.side_effect = (
29
+ ["0x1"] # activityChecker
30
+ + [nested_result] # getServiceInfo
31
+ + [2000] * 5 # getNextRewardCheckpointTimestamp and any others
32
+ )
33
+
41
34
  # Re-init to trigger calls
42
35
  with (
43
36
  patch("iwa.plugins.olas.contracts.staking.ActivityCheckerContract"),
@@ -45,7 +38,8 @@ def test_staking_get_service_info_nested_tuple(mock_staking):
45
38
  ):
46
39
  mock_ci.get_instance.return_value.web3.eth.contract.return_value = MagicMock()
47
40
  staking = StakingContract("0x78731D3Ca6b7E34aC0F824c42a7cC18A495cabaB", "gnosis")
48
- staking.call = MagicMock(side_effect=[nested_result, 2000])
41
+ # Update call on the new instance
42
+ staking.call = MagicMock(side_effect=mock_staking.call.side_effect)
49
43
  staking.activity_checker.get_multisig_nonces.return_value = (1, 3)
50
44
  staking.get_required_requests = MagicMock(return_value=5)
51
45
 
@@ -0,0 +1,38 @@
1
+ """Script to verify ChainlistRPC functionality."""
2
+ from iwa.core.chainlist import ChainlistRPC
3
+
4
+
5
+ def main() -> None:
6
+ """Run the verification script."""
7
+ print("Initializing ChainlistRPC...")
8
+ chainlist = ChainlistRPC()
9
+
10
+ print("Fetching data...")
11
+ chainlist.fetch_data()
12
+
13
+ gnosis_chain_id = 100
14
+ print(f"\n--- Gnosis Chain (ID: {gnosis_chain_id}) ---")
15
+
16
+ all_rpcs = chainlist.get_rpcs(gnosis_chain_id)
17
+ print(f"Total RPCs found: {len(all_rpcs)}")
18
+
19
+ https_rpcs = chainlist.get_https_rpcs(gnosis_chain_id)
20
+ print(f"HTTPS RPCs ({len(https_rpcs)}):")
21
+ for url in https_rpcs[:5]:
22
+ print(f" - {url}")
23
+ if len(https_rpcs) > 5:
24
+ print(" ... and more")
25
+
26
+ wss_rpcs = chainlist.get_wss_rpcs(gnosis_chain_id)
27
+ print(f"WSS RPCs ({len(wss_rpcs)}):")
28
+ for url in wss_rpcs[:5]:
29
+ print(f" - {url}")
30
+ if len(wss_rpcs) > 5:
31
+ print(" ... and more")
32
+
33
+ print("\nTracking info for first 5 RPCs:")
34
+ for node in all_rpcs[:5]:
35
+ print(f" - {node.url}: Tracking={node.is_tracking} (Privacy={node.privacy}, Tracking={node.tracking})")
36
+
37
+ if __name__ == "__main__":
38
+ main()
@@ -105,16 +105,21 @@ def _check_availability(name, address, interface):
105
105
  """Check availability of a single staking contract."""
106
106
  # Import at module level would cause circular import, but we can cache it
107
107
  # The import is cached by Python after first call so this is efficient
108
+ from iwa.core.contracts.cache import ContractCache
108
109
  from iwa.plugins.olas.contracts.staking import StakingContract
109
110
 
110
111
  try:
111
- contract = StakingContract(address, chain_name=interface.chain.name)
112
+ # Use ContractCache to benefit from shared instances and property caching
113
+ contract = ContractCache().get_contract(
114
+ StakingContract, address, chain_name=interface.chain.name
115
+ )
112
116
 
113
117
  # StakingContract uses .call() which handles with_retry and rotation
118
+ # Use properties instead of .call() to leverage caching
114
119
  service_ids = contract.call("getServiceIds")
115
- max_services = contract.call("maxNumServices")
116
- min_deposit = contract.call("minStakingDeposit")
117
- staking_token = contract.call("stakingToken")
120
+ max_services = contract.max_num_services
121
+ min_deposit = contract.min_staking_deposit
122
+ staking_token = contract.staking_token_address
118
123
  used = len(service_ids)
119
124
 
120
125
  return {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iwa
3
- Version: 0.0.19
3
+ Version: 0.0.20
4
4
  Summary: A secure, modular, and plugin-based framework for crypto agents and ops
5
5
  Requires-Python: <4.0,>=3.12
6
6
  Description-Content-Type: text/markdown
@@ -1,8 +1,9 @@
1
1
  iwa/__init__.py,sha256=vu12UytYNREtMRvIWp6AfV1GgUe53XWwCMhYyqKAPgo,19
2
2
  iwa/__main__.py,sha256=eJU5Uxeu9Y7shWg5dt5Mcq0pMC4wFVNWjeYGKSf4Apw,88
3
3
  iwa/core/__init__.py,sha256=GJv4LJOXeZ3hgGvbt5I6omkoFkP2A9qhHjpDlOep9ik,24
4
+ iwa/core/chainlist.py,sha256=IOnlfRFaPlzdg91HbILynzvRfEJ9afikjFUS06K4rfU,4021
4
5
  iwa/core/cli.py,sha256=GCrHSUp5W1KdLHoWbk0aCLTphkKDLROoFh82uyUqdY8,7729
5
- iwa/core/constants.py,sha256=En-1uT5Anv0_NCSMdQjTGvjqiNAWfbSb_kGlH4Ct0Ag,966
6
+ iwa/core/constants.py,sha256=_CYUVQpR--dRPuxotsmbzQE-22y61tlnjUD7IhlvVVA,997
6
7
  iwa/core/db.py,sha256=WI-mP0tQAmwFPeEi9w7RCa_Mcf_zBfd_7JcbHJwU1aU,10377
7
8
  iwa/core/ipfs.py,sha256=aHjq_pflgwDVHl8g5EMQv0q2RAmMs-a0pOTVsj_L5xE,4980
8
9
  iwa/core/keys.py,sha256=ckacVZxm_02V9hlmHIxz-CkxjXdGHqvGGAXfO6EeHCw,22365
@@ -11,6 +12,7 @@ iwa/core/models.py,sha256=kBQ0cBe6uFmL2QfW7mjKiMFeZxhT-FRN-RyK3Ko0vE8,12849
11
12
  iwa/core/monitor.py,sha256=OmhKVMkfhvtxig3wDUL6iGwBIClTx0YUqMncCao4SqI,7953
12
13
  iwa/core/plugins.py,sha256=FLvOG4S397fKi0aTH1fWBEtexn4yvGv_QzGWqFrhSKE,1102
13
14
  iwa/core/pricing.py,sha256=uENpqVMmuogZHctsLuEsU7WJ1cLSNAI-rZTtbpTDjeQ,4048
15
+ iwa/core/rpc_monitor.py,sha256=-NHR1Mn2IJKJ9x975NGfsze_shI12yL0OyTPtmjUMKg,1661
14
16
  iwa/core/secrets.py,sha256=U7DZKrwKuSOFV00Ij3ISrrO1cWn_t1GBW_0PyAqjcD4,2588
15
17
  iwa/core/tables.py,sha256=y7Cg67PAGHYVMVyAjbo_CQ9t2iz7UXE-OTuUHRyFRTo,2021
16
18
  iwa/core/test.py,sha256=gey0dql5eajo1itOhgkSrgfyGWue2eSfpr0xzX3vc38,643
@@ -25,7 +27,8 @@ iwa/core/chain/manager.py,sha256=cFEzh6pK5OyVhjhpeMAqhc9RnRDQR1DjIGiGKp-FXBI,115
25
27
  iwa/core/chain/models.py,sha256=0OgBo08FZEQisOdd00YUMXSAV7BC0CcWpqJ2y-gs0cI,4863
26
28
  iwa/core/chain/rate_limiter.py,sha256=gU7TmWdH9D_wbXKT1X7mIgoIUCWVuebgvRhxiyLGAmI,6613
27
29
  iwa/core/contracts/__init__.py,sha256=P5GFY_pnuI02teqVY2U0t98bn1_SSPAbcAzRMpCdTi4,34
28
- iwa/core/contracts/contract.py,sha256=N2I4-38O_6awqVrTEdJFh4XhsMbeu2JtFvkboUC4ZMg,12517
30
+ iwa/core/contracts/cache.py,sha256=7wGQgyXAmofvx-irbxSnGgIDzQik6Pcpm7up6wMQcoo,4454
31
+ iwa/core/contracts/contract.py,sha256=DCSQmlOom_SkGXElcr1VQyAt2nt0GjkYhLpiQsWDJPY,12810
29
32
  iwa/core/contracts/erc20.py,sha256=VqriOdUXej0ilTgpukpm1FUF_9sSrVMAPuEpIvyZ2SQ,2646
30
33
  iwa/core/contracts/multisend.py,sha256=tSdBCWe7LSdBoKZ7z2QebmRFK4M2ln7H3kmJBeEb4Ho,2431
31
34
  iwa/core/contracts/abis/erc20.json,sha256=vrdExMWcIogg_nO59j1Pmipmpa2Ulj3oCCdcdrrFVCE,16995
@@ -57,17 +60,18 @@ iwa/plugins/gnosis/tests/test_cow.py,sha256=iVy5ockMIcPZWsX4WGXU91DhBsYEZ5NOxtFz
57
60
  iwa/plugins/gnosis/tests/test_safe.py,sha256=pw1zrYvAiVtmPIU5k7BtOQpDNAQTSTrLIaeljCjSahc,3216
58
61
  iwa/plugins/olas/__init__.py,sha256=_NhBczzM61fhGYwGhnWfEeL8Jywyy_730GASe2BxzeQ,106
59
62
  iwa/plugins/olas/constants.py,sha256=iTFoO2QW3KbhL5k5sKsJxxyDytl9wVIb_9hAih55KrE,7728
63
+ iwa/plugins/olas/events.py,sha256=SWD3wYdQ-l6dLUJSkfh_WsLmedH4Vsw_EvYXg7QC3yc,5970
60
64
  iwa/plugins/olas/importer.py,sha256=f8KlZ9dGcNbpg8uoTYbO9sDvbluZoslhpWFLqPjPnLA,26717
61
65
  iwa/plugins/olas/mech_reference.py,sha256=CaSCpQnQL4F7wOG6Ox6Zdoy-uNEQ78YBwVLILQZKL8Q,5782
62
66
  iwa/plugins/olas/models.py,sha256=xC5hYakX53pBT6zZteM9cyiC7t6XRLLpobjQmDYueOo,3520
63
67
  iwa/plugins/olas/plugin.py,sha256=S_vnvZ02VdVWD7N5kp7u5JIRQ2JLtfwGDZ7OHkAN0M8,9390
64
- iwa/plugins/olas/contracts/activity_checker.py,sha256=PTLvsFdi3PdsFMxRVcXfwlQMRyJYHIzrHf3OaPVtFqU,3943
68
+ iwa/plugins/olas/contracts/activity_checker.py,sha256=WXxuzbpXGVqIfEiMPiiqN3Z_UxIY-Lvx0raa1ErBfPA,5323
65
69
  iwa/plugins/olas/contracts/base.py,sha256=y73aQbDq6l4zUpz_eQAg4MsLkTAEqjjupXlcvxjfgCI,240
66
70
  iwa/plugins/olas/contracts/mech.py,sha256=dXYtyORc-oiu9ga5PtTquOFkoakb6BLGKvlUsteygIg,2767
67
71
  iwa/plugins/olas/contracts/mech_marketplace.py,sha256=hMADl5MQGvT2wLRKu4vHGe4RrAZVq8Y2M_EvXWWz528,1554
68
72
  iwa/plugins/olas/contracts/mech_marketplace_v1.py,sha256=ooF5uw1wxwYsoriGUGGxXxmaD8DtWZtK4TJBCUNTGtI,2501
69
73
  iwa/plugins/olas/contracts/service.py,sha256=BDQKeCTCnBNrwKD1a8rrlLytpKG3CAdjr-s0ec-dsFY,8243
70
- iwa/plugins/olas/contracts/staking.py,sha256=vt2UZ6G0edg1EbPrzFK5AIse531bQTu4PLydQ6rgrAA,14494
74
+ iwa/plugins/olas/contracts/staking.py,sha256=TimiHSJy5wAlx35uplyeG7TG6NpxPigkmKcrz_ZBCjY,18487
71
75
  iwa/plugins/olas/contracts/abis/activity_checker.json,sha256=HT0IMbyTLMO71ITBKwoS950rHe772suPP4b8eDAodJ0,2230
72
76
  iwa/plugins/olas/contracts/abis/mech.json,sha256=bMMCXInjE_2PTPnc_sIyS_H8pod5Sm_e-xTbKgZppKc,16369
73
77
  iwa/plugins/olas/contracts/abis/mech_marketplace.json,sha256=KPnF-H_UATb3wdb_7o6ky_hSp5xwgvckD-QqylsWJLg,32468
@@ -81,17 +85,17 @@ iwa/plugins/olas/contracts/abis/staking_token.json,sha256=cuUOmi1s4Z6VSIX0an_IxK
81
85
  iwa/plugins/olas/scripts/test_full_mech_flow.py,sha256=Fqoq5bn7Z_3YyRrnuqNAZy9cwQDLiXP6Vf3EIeWPo2I,9024
82
86
  iwa/plugins/olas/scripts/test_simple_lifecycle.py,sha256=8T50tOZx3afeECSfCNAb0rAHNtYOsBaeXlMwKXElCk8,2099
83
87
  iwa/plugins/olas/service_manager/__init__.py,sha256=GXiThMEY3nPgHUl1i-DLrF4h96z9jPxxI8Jepo2E1PM,1926
84
- iwa/plugins/olas/service_manager/base.py,sha256=CCTH7RiYtgyFwRszrMLxNf1rNM_6leWHuJJmse4m2wI,4854
88
+ iwa/plugins/olas/service_manager/base.py,sha256=EBPg0ymqgtAb7ZvVSfTt31QYgv_6gp4UAc6je00NLAg,5009
85
89
  iwa/plugins/olas/service_manager/drain.py,sha256=IS7YYKuQdkULcNdxfHVzjcq95pXKdpajolzLL78u4jc,12430
86
- iwa/plugins/olas/service_manager/lifecycle.py,sha256=DIB6yrP0VPICu6558uQJuFp2sgrA66iVNTzZVUUowGw,47159
87
- iwa/plugins/olas/service_manager/mech.py,sha256=WJtf90y9JrFAo6QHosFn0bfM_2q9VjMBmXhYzwDsUpU,27620
88
- iwa/plugins/olas/service_manager/staking.py,sha256=Z9GzlPfY7qSSjc9xPhWvb9qywxu_7OB3Gc1eBli07pY,28058
90
+ iwa/plugins/olas/service_manager/lifecycle.py,sha256=Lr2O3Vmv8dLlzwUVt_Ga8bFRQD3TbrM6LGs5kKeiAOE,48410
91
+ iwa/plugins/olas/service_manager/mech.py,sha256=NVzVbEmyOe3wK92VEzCCOSuy3HDkEP1MSoVt7Av8Psk,27949
92
+ iwa/plugins/olas/service_manager/staking.py,sha256=7REp_HziKtqF9uSvbcq01C9XiaxgVT3gCimuLAAdNnM,28219
89
93
  iwa/plugins/olas/tests/conftest.py,sha256=4vM7EI00SrTGyeP0hNzsGSQHEj2-iznVgzlNh2_OGfo,739
90
94
  iwa/plugins/olas/tests/test_importer.py,sha256=i9LKov7kNRECB3hmRnhKBwcfx3uxtjWe4BB77bOOpeo,4282
91
95
  iwa/plugins/olas/tests/test_importer_error_handling.py,sha256=X37TrvJ6-3-NuJ2megm0Cnx3KJdA1wke563pRf_EPJk,12084
92
96
  iwa/plugins/olas/tests/test_mech_contracts.py,sha256=wvxuigPafF-ySIHVBdWVei3AO418iPh7cSVdAlUGm_s,3566
93
97
  iwa/plugins/olas/tests/test_olas_contracts.py,sha256=B8X-5l1KfYMoZOiM94_rcNzbILLl78rqt_jhyxzAOqE,10835
94
- iwa/plugins/olas/tests/test_olas_integration.py,sha256=uIA9NB1iaOSTOaPgY5gRvrFxFLeq6Z93239yi2qzj1g,20488
98
+ iwa/plugins/olas/tests/test_olas_integration.py,sha256=vjL8-RNdxXu6RFR5F1Bn7xqnxnUVWTzl2--Pp7-0r5A,22973
95
99
  iwa/plugins/olas/tests/test_olas_models.py,sha256=5scX-wvRLGH3G44S2okq_tyQ9Rk7Pd0Ak1zNCZ2HtI4,4957
96
100
  iwa/plugins/olas/tests/test_olas_view.py,sha256=kh3crsriyoRiZC6l8vzGllocvQnYmqziv-csbmXih0E,10489
97
101
  iwa/plugins/olas/tests/test_olas_view_actions.py,sha256=jAxr9bjFNAaxGf1btIrxdMaHgJ0PWX9aDwVU-oPGMpk,5109
@@ -99,15 +103,15 @@ iwa/plugins/olas/tests/test_olas_view_modals.py,sha256=8j0PNFjKqFC5V1kBdVFWNLMvq
99
103
  iwa/plugins/olas/tests/test_plugin.py,sha256=RVgU-Cq6t_3mOh90xFAGwlJOV7ZIgp0VNaK5ZAxisAQ,2565
100
104
  iwa/plugins/olas/tests/test_plugin_full.py,sha256=xevLYmdU4zd5FyEEEn9gvzGimPztmt6vymybeZHXnq8,8507
101
105
  iwa/plugins/olas/tests/test_service_lifecycle.py,sha256=sOCtpz8T9s55AZe9AoqP1h3XrXw5NDSjDqwLgYThvU4,5559
102
- iwa/plugins/olas/tests/test_service_manager.py,sha256=wUdgB_73WtMxzpO3olMCwet9v9EudGr9uQyXeF9o_yE,40380
103
- iwa/plugins/olas/tests/test_service_manager_errors.py,sha256=M49aZQYVBvPAEvJdpJO6gN8wC1tUdHnln7XxmqO_O50,8151
104
- iwa/plugins/olas/tests/test_service_manager_flows.py,sha256=lxkXdK2Ht92wAywMUyXYYRfkR3boixzGGF47MEgcq54,19418
106
+ iwa/plugins/olas/tests/test_service_manager.py,sha256=rS2m0A26apc-o4HsfP5oXmVcmZSR5e874bjhQKZRaSg,40650
107
+ iwa/plugins/olas/tests/test_service_manager_errors.py,sha256=udlAsQj_t1F5TwVQuWhroF6jDJ4RmGEXaxPh87tMsuA,8538
108
+ iwa/plugins/olas/tests/test_service_manager_flows.py,sha256=QvRFpJIapZXbagxPApr-995i64aJDapxSFyae8tNSHU,20722
105
109
  iwa/plugins/olas/tests/test_service_manager_mech.py,sha256=qG6qu5IPRNypXUsblU2OEkuiuwDJ0TH8RXZbibmTFcQ,4937
106
110
  iwa/plugins/olas/tests/test_service_manager_rewards.py,sha256=hIVckGl5rEr-KHGNUxxVopal0Tpw4EZharBt0MbaCVA,11798
107
111
  iwa/plugins/olas/tests/test_service_manager_validation.py,sha256=ajlfH5uc4mAHf8A7GLE5cW7X8utM2vUilM0JdGDdlVg,5382
108
- iwa/plugins/olas/tests/test_service_staking.py,sha256=XkC8H_qVumOQ1i4_vidEdXqkK5stInd2tgT50l0SRMk,12201
112
+ iwa/plugins/olas/tests/test_service_staking.py,sha256=miNGZZoIrZf0Am-pJ8gTyvVAruL4P7jMvrtFEhG5wxQ,15694
109
113
  iwa/plugins/olas/tests/test_staking_integration.py,sha256=QCBQf6P2ZmmsEGt2k8W2r53lG2aVRuoMJE-aFxVDLss,9701
110
- iwa/plugins/olas/tests/test_staking_validation.py,sha256=J7DgDdIiVTkKv_7obtSHQ2lgfUGPmUwuPjTUkiT4cbs,4198
114
+ iwa/plugins/olas/tests/test_staking_validation.py,sha256=uug64jFcXYJ3Nw_lNa3O4fnhNr5wAWHHIrchSbR2MVE,4020
111
115
  iwa/plugins/olas/tui/__init__.py,sha256=5ZRsbC7J3z1xfkZRiwr4bLEklf78rNVjdswe2p7SlS8,28
112
116
  iwa/plugins/olas/tui/olas_view.py,sha256=qcPxhurDPJjHWln6R64ZVAJ2h82IXzw48unhRvQVZqQ,36448
113
117
  iwa/tools/__init__.py,sha256=jQyuwDQGRigSe7S9JMb4yK3CXPgZFJNffzt6N2v9PU0,21
@@ -117,6 +121,7 @@ iwa/tools/release.py,sha256=-Z9GG6Y-K6KG32K0VUf_MruiUdJxG6W7ToOMzhyCH7Y,3963
117
121
  iwa/tools/reset_env.py,sha256=FKN0wuh9Xq00c94B2kEFehHPKcWldxYqgU45yJwg5Cg,3140
118
122
  iwa/tools/reset_tenderly.py,sha256=usKfOLrQvdCzEncueg-Sz3spqX80vHPQmbh2tIygo8o,11295
119
123
  iwa/tools/restore_backup.py,sha256=_LJbmKv9SlekLUQFdjI3aHCvAc6uePobJe3bQEFyatk,2455
124
+ iwa/tools/test_chainlist.py,sha256=9J06sTsKgnEcN7WSn-YgJkCHhfbGDdVS-KNMDBhYllA,1143
120
125
  iwa/tools/wallet_check.py,sha256=IQLgb8oCt4oG6FMEAqzUxM57DLv_UE24dFUSVxtBo_Y,4774
121
126
  iwa/tui/__init__.py,sha256=XYIZNQNy-fZC1NHHM0sd9qUO0vE1slml-cm0CpQ4NLY,27
122
127
  iwa/tui/app.py,sha256=XDQ4nAPGBwhrEmdL_e3V8oYSOho8pY7jsd3C_wk92UU,4163
@@ -144,7 +149,7 @@ iwa/web/routers/olas/admin.py,sha256=PMRdNelqYgQ1xbqh3floFV5xrVtBRQiwZPd8J9_ffxg
144
149
  iwa/web/routers/olas/funding.py,sha256=f8fADNtbZEBFl-vuVKfas6os38Vot6K5tJBTenZmCD0,4832
145
150
  iwa/web/routers/olas/general.py,sha256=dPsBQppTGoQY1RztliUhseOHOZGeeCR10lhThD9kyXo,803
146
151
  iwa/web/routers/olas/services.py,sha256=IpjvkpJeCwREbdHt47gov-fvTl9bY4EBUmZZZEHi3iI,16310
147
- iwa/web/routers/olas/staking.py,sha256=N1pMcPjhpfSPi7Sl7XIIAPoFxf0hptdvkUqkTtgqPcc,12424
152
+ iwa/web/routers/olas/staking.py,sha256=Ak29SIIMNAgPqIij6sdNAG4z7LUeUGRVRpplZw4hsAU,12666
148
153
  iwa/web/static/app.js,sha256=CWm_TR2nKSDe8z0-nUQp7VaBHIGJg7mAOU-XJDveFsk,113487
149
154
  iwa/web/static/index.html,sha256=q7s7plnMbN1Nkzr5bRxZgvgOFerUChEGIZW7SpAVtPc,28514
150
155
  iwa/web/static/style.css,sha256=aTtE42mmfYV6y7xfo9cUgUhT8x-KyNC1zmPjSdskxIk,24315
@@ -152,7 +157,7 @@ iwa/web/tests/test_web_endpoints.py,sha256=C264MH-CTyDW4GLUrTXBgLJKUk4-89pFAScBd
152
157
  iwa/web/tests/test_web_olas.py,sha256=0CVSsrncOeJ3x0ECV7mVLQV_CXZRrOqGiVjgLIi6hZ8,16308
153
158
  iwa/web/tests/test_web_swap.py,sha256=7A4gBJFL01kIXPtW1E1J17SCsVc_0DmUn-R8kKrnnVA,2974
154
159
  iwa/web/tests/test_web_swap_coverage.py,sha256=zGNrzlhZ_vWDCvWmLcoUwFgqxnrp_ACbo49AtWBS_Kw,5584
155
- iwa-0.0.19.dist-info/licenses/LICENSE,sha256=eIubm_IlBHPYRQlLNZKbBNKhJUUP3JH0A2miZUhAVfI,1078
160
+ iwa-0.0.20.dist-info/licenses/LICENSE,sha256=eIubm_IlBHPYRQlLNZKbBNKhJUUP3JH0A2miZUhAVfI,1078
156
161
  tests/legacy_cow.py,sha256=oOkZvIxL70ReEoD9oHQbOD5GpjIr6AGNHcOCgfPlerU,8389
157
162
  tests/legacy_safe.py,sha256=AssM2g13E74dNGODu_H0Q0y412lgqsrYnEzI97nm_Ts,2972
158
163
  tests/legacy_transaction_retry_logic.py,sha256=D9RqZ7DBu61Xr2djBAodU2p9UE939LL-DnQXswX5iQk,1497
@@ -183,6 +188,7 @@ tests/test_plugin_service.py,sha256=ZEe37kV_sv4Eb04032O1hZIoo9yf5gJo83ks7Grzrng,
183
188
  tests/test_pricing.py,sha256=ptu_2Csc6d64bIzMMw3TheJge2Kfn05Gs-twz_KmBzg,5276
184
189
  tests/test_rate_limiter.py,sha256=DOIlrBP2AtVFHCpznIoFn2FjFc33emG7M_FffLh4MGE,7314
185
190
  tests/test_reset_tenderly.py,sha256=GVoqbDT3n4_GnlKF5Lx-8ew15jT8I2hIPdTulQDb6dI,7215
191
+ tests/test_rpc_efficiency.py,sha256=EEcBlbUXEi9JVBorLU7mK7mmK0vcFt53KhefHr1oPQc,3741
186
192
  tests/test_rpc_rotation.py,sha256=YU21TrMnEbcb36zu_L8dpCSbaHX7CkqXLjipz1swkkc,10554
187
193
  tests/test_rpc_view.py,sha256=sgZ53KEHl8VGb7WKYa0VI7Cdxbf8JH1SdroHYbWHjfQ,2031
188
194
  tests/test_safe_coverage.py,sha256=g9Bdrpkc-Mc8HBjk07lYNRkzxWZiF922uiVLZqhehBE,5093
@@ -204,8 +210,8 @@ tests/test_utils.py,sha256=vkP49rYNI8BRzLpWR3WnKdDr8upeZjZcs7Rx0pjbQMo,1292
204
210
  tests/test_workers.py,sha256=MInwdkFY5LdmFB3o1odIaSD7AQZb3263hNafO1De5PE,2793
205
211
  tools/create_and_stake_service.py,sha256=1xwy_bJQI1j9yIQ968Oc9Db_F6mk1659LuuZntTASDE,3742
206
212
  tools/verify_drain.py,sha256=PkMjblyOOAuQge88FwfEzRtCYeEtJxXhPBmtQYCoQ-8,6743
207
- iwa-0.0.19.dist-info/METADATA,sha256=ueADSL3j41OZTVAxdOovoGm6S4pPn9g2M4g2l7yVRgM,7295
208
- iwa-0.0.19.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
209
- iwa-0.0.19.dist-info/entry_points.txt,sha256=nwB6kscrfA7M00pYmL2j-sBH6eF6h2ga9IK1BZxdiyQ,241
210
- iwa-0.0.19.dist-info/top_level.txt,sha256=kedS9cRUbm4JE2wYeabIXilhHjN8KCw0IGbqqqsw0Bs,16
211
- iwa-0.0.19.dist-info/RECORD,,
213
+ iwa-0.0.20.dist-info/METADATA,sha256=_ERQ1f_nDtVFZClmaQ4vW6o6Yso2JjqumBbS56JJCCs,7295
214
+ iwa-0.0.20.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
215
+ iwa-0.0.20.dist-info/entry_points.txt,sha256=nwB6kscrfA7M00pYmL2j-sBH6eF6h2ga9IK1BZxdiyQ,241
216
+ iwa-0.0.20.dist-info/top_level.txt,sha256=kedS9cRUbm4JE2wYeabIXilhHjN8KCw0IGbqqqsw0Bs,16
217
+ iwa-0.0.20.dist-info/RECORD,,
@@ -0,0 +1,103 @@
1
+ from unittest.mock import MagicMock, patch
2
+
3
+ import pytest
4
+
5
+ from iwa.core.contracts.cache import ContractCache
6
+ from iwa.plugins.olas.contracts.staking import StakingContract
7
+
8
+
9
+ @pytest.fixture
10
+ def mock_chain_interface():
11
+ with patch("iwa.core.contracts.contract.ChainInterfaces") as mock_chains:
12
+ mock_interface = MagicMock()
13
+ mock_chains.return_value.get.return_value = mock_interface
14
+
15
+ # Mock web3 and contract
16
+ mock_web3_backend = MagicMock()
17
+ mock_interface.web3._web3 = mock_web3_backend
18
+
19
+ mock_contract = MagicMock()
20
+ mock_web3_backend.eth.contract.return_value = mock_contract
21
+
22
+ # Mock with_retry to execute the function
23
+ mock_interface.with_retry.side_effect = lambda func, **kwargs: func()
24
+
25
+ # Yield both interface and contract mock
26
+ yield mock_interface, mock_contract
27
+
28
+ def test_staking_contract_lazy_loading(mock_chain_interface):
29
+ """Verify StakingContract init does NOT make RPC calls."""
30
+ mock_interface, mock_contract = mock_chain_interface
31
+
32
+ # Reset ContractCache
33
+ ContractCache().clear()
34
+
35
+ # Instantiate logic
36
+ contract = StakingContract(address="0x123", chain_name="gnosis")
37
+
38
+ # Assert NO calls to call yet (since we mock with_retry to execute immediately, 0 calls means 0 executions)
39
+ assert mock_interface.with_retry.call_count == 0
40
+
41
+ # Setup return value
42
+ # livenessPeriod is a property that calls "livenessPeriod" on contract
43
+ mock_contract.functions.livenessPeriod.return_value.call.return_value = 3600
44
+
45
+ # Access property
46
+ val = contract.liveness_period
47
+ assert val == 3600
48
+
49
+ # Assert 1 call
50
+ assert mock_contract.functions.livenessPeriod.return_value.call.call_count == 1
51
+
52
+ # Access again
53
+ val = contract.liveness_period
54
+
55
+ # Assert still 1 call (cached)
56
+ assert mock_contract.functions.livenessPeriod.return_value.call.call_count == 1
57
+
58
+ def test_contract_cache_singleton(mock_chain_interface):
59
+ """Verify ContractCache returns same instance and reuses property cache."""
60
+ mock_interface, mock_contract = mock_chain_interface
61
+ ContractCache().clear()
62
+
63
+ c1 = ContractCache().get_contract(StakingContract, "0xABC", "gnosis")
64
+ c2 = ContractCache().get_contract(StakingContract, "0xabc", "gnosis") # Check ignore case
65
+
66
+ assert c1 is c2
67
+
68
+ # populate cache on c1
69
+ mock_contract.functions.maxNumServices.return_value.call.return_value = 500
70
+
71
+ val1 = c1.max_num_services
72
+ assert val1 == 500
73
+ assert mock_contract.functions.maxNumServices.return_value.call.call_count == 1
74
+
75
+ # access on c2
76
+ val2 = c2.max_num_services
77
+ assert val2 == 500
78
+ # Call count should NOT increase
79
+ assert mock_contract.functions.maxNumServices.return_value.call.call_count == 1
80
+
81
+ def test_epoch_aware_caching(mock_chain_interface):
82
+ """Verify ts_checkpoint caching logic."""
83
+ mock_interface, mock_contract = mock_chain_interface
84
+ ContractCache().clear()
85
+ contract = StakingContract(address="0xEpoch", chain_name="gnosis")
86
+
87
+ # Mock return values for tsCheckpoint
88
+ # We use side_effect on the call() method to simulate changing return values if needed
89
+ # But here we just want it to return 1000 once
90
+ mock_contract.functions.tsCheckpoint.return_value.call.return_value = 1000
91
+
92
+ # Set liveness period in cache to avoid RPC call for it
93
+ contract._contract_params_cache["livenessPeriod"] = 600
94
+
95
+ # 1. Fetch ts_checkpoint
96
+ ts = contract.ts_checkpoint()
97
+ assert ts == 1000
98
+ assert mock_contract.functions.tsCheckpoint.return_value.call.call_count == 1
99
+
100
+ # 2. Call again - should be cached
101
+ ts2 = contract.ts_checkpoint()
102
+ assert ts2 == 1000
103
+ assert mock_contract.functions.tsCheckpoint.return_value.call.call_count == 1
File without changes