iwa 0.0.10__py3-none-any.whl → 0.0.11__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.
@@ -28,6 +28,50 @@ class CreateServiceRequest(BaseModel):
28
28
  )
29
29
 
30
30
 
31
+ def _determine_bond_amount(req: CreateServiceRequest) -> int:
32
+ """Determine the bond amount required for the service."""
33
+ from web3 import Web3
34
+
35
+ from iwa.core.contracts.erc20 import ERC20Contract
36
+ from iwa.plugins.olas.contracts.staking import StakingContract
37
+ from iwa.web.dependencies import wallet
38
+
39
+ # Default to 1 wei of the service token if no staking contract specified
40
+ bond_amount = Web3.to_wei(1, "wei")
41
+
42
+ if req.token_address and req.staking_contract:
43
+ # If a contract is specified, we MUST use its requirements
44
+ logger.info(f"Fetching requirements from {req.staking_contract}...")
45
+ staking_contract = StakingContract(req.staking_contract, req.chain)
46
+ reqs = staking_contract.get_requirements()
47
+ bond_amount = reqs["required_agent_bond"]
48
+ min_staking_deposit = reqs["min_staking_deposit"]
49
+ logger.info(f"Required bond amount from contract: {bond_amount} wei")
50
+ logger.info(f"Required min_staking_deposit: {min_staking_deposit} wei")
51
+
52
+ # Validate upfront: total OLAS needed = bond + min_staking_deposit
53
+ if req.stake_on_create:
54
+ total_olas_needed = bond_amount + min_staking_deposit
55
+ logger.info(
56
+ f"Total OLAS needed for create + stake: {total_olas_needed / 1e18:.2f} OLAS"
57
+ )
58
+
59
+ # Check owner balance (master is default owner for new services)
60
+ staking_token = reqs.get("staking_token")
61
+ if staking_token:
62
+ erc20 = ERC20Contract(staking_token, req.chain)
63
+ owner_balance = erc20.balance_of_wei(wallet.master_account.address)
64
+ logger.info(f"Owner OLAS balance: {owner_balance / 1e18:.2f} OLAS")
65
+
66
+ if owner_balance < total_olas_needed:
67
+ raise HTTPException(
68
+ status_code=400,
69
+ detail=f"Insufficient OLAS balance. Need {total_olas_needed / 1e18:.2f} OLAS "
70
+ f"(bond: {bond_amount / 1e18:.2f} + deposit: {min_staking_deposit / 1e18:.2f}), "
71
+ f"but owner has {owner_balance / 1e18:.2f} OLAS",
72
+ )
73
+ return bond_amount
74
+
31
75
  @router.post(
32
76
  "/create",
33
77
  summary="Create Service",
@@ -36,28 +80,14 @@ class CreateServiceRequest(BaseModel):
36
80
  def create_service(req: CreateServiceRequest, auth: bool = Depends(verify_auth)):
37
81
  """Create a new Olas service using spin_up for seamless deployment."""
38
82
  try:
39
- from web3 import Web3
40
83
 
41
84
  from iwa.plugins.olas.contracts.staking import StakingContract
42
85
  from iwa.plugins.olas.service_manager import ServiceManager
43
86
 
44
87
  manager = ServiceManager(wallet)
45
88
 
46
- # Determine bond amount based on staking contract
47
- bond_amount = 1 # Default for native token (1 wei)
48
-
49
- staking_contract = None
50
- if req.token_address:
51
- if req.staking_contract:
52
- # If a contract is specified, we MUST use its requirements
53
- logger.info(f"Fetching requirements from {req.staking_contract}...")
54
- staking_contract = StakingContract(req.staking_contract, req.chain)
55
- reqs = staking_contract.get_requirements()
56
- bond_amount = reqs["required_agent_bond"]
57
- logger.info(f"Required bond amount from contract: {bond_amount} wei")
58
- else:
59
- # Default to 1 wei of the service token if no staking contract specified
60
- bond_amount = Web3.to_wei(1, "wei")
89
+ # Determine bond amount
90
+ bond_amount = _determine_bond_amount(req)
61
91
 
62
92
  # Step 1: Create the service (PRE_REGISTRATION state)
63
93
  logger.info(
@@ -87,11 +117,14 @@ def create_service(req: CreateServiceRequest, auth: bool = Depends(verify_auth))
87
117
 
88
118
  # Step 2: Spin up the service (activate → register → deploy → optionally stake)
89
119
  # Only pass staking_contract if user wants to stake on create
90
- spin_up_staking = staking_contract if req.stake_on_create else None
120
+ staking_obj = None
121
+ if req.stake_on_create and req.staking_contract:
122
+ # We need to instantiate the staking contract object for spin_up
123
+ staking_obj = StakingContract(req.staking_contract, req.chain)
91
124
 
92
125
  success = manager.spin_up(
93
126
  service_id=service_id,
94
- staking_contract=spin_up_staking,
127
+ staking_contract=staking_obj,
95
128
  bond_amount_wei=bond_amount,
96
129
  )
97
130
 
@@ -110,7 +143,7 @@ def create_service(req: CreateServiceRequest, auth: bool = Depends(verify_auth))
110
143
  "service_key": manager.service.key if manager.service else None,
111
144
  "multisig": str(manager.service.multisig_address) if manager.service else None,
112
145
  "final_state": final_state,
113
- "staked": req.stake_on_create and spin_up_staking is not None,
146
+ "staked": req.stake_on_create and staking_obj is not None,
114
147
  }
115
148
 
116
149
  except HTTPException:
@@ -140,11 +140,17 @@ def _check_availability(name, address, interface):
140
140
 
141
141
 
142
142
  def _fetch_all_contracts(contracts: dict, interface) -> list:
143
- """Fetch availability for all contracts using threads."""
143
+ """Fetch availability for all contracts using threads.
144
+
145
+ Note: Using limited parallelism (2 workers) to avoid overwhelming RPC
146
+ endpoints with parallel requests that cause 429 rate limit errors.
147
+ The RPC rotation mechanism is global but Contract objects are thread-local,
148
+ so excessive parallelism leads to stale providers being used.
149
+ """
144
150
  from concurrent.futures import ThreadPoolExecutor
145
151
 
146
152
  results = []
147
- with ThreadPoolExecutor(max_workers=10) as executor:
153
+ with ThreadPoolExecutor(max_workers=2) as executor:
148
154
  futures = [
149
155
  executor.submit(_check_availability, name, addr, interface)
150
156
  for name, addr in contracts.items()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iwa
3
- Version: 0.0.10
3
+ Version: 0.0.11
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
@@ -17,10 +17,10 @@ iwa/core/test.py,sha256=gey0dql5eajo1itOhgkSrgfyGWue2eSfpr0xzX3vc38,643
17
17
  iwa/core/types.py,sha256=EfDfIwLajTNK-BP9K17QLOIsGCs8legplKI_bUD_NjM,1992
18
18
  iwa/core/ui.py,sha256=DglmrI7XhUmOpLn9Nog9Cej4r-VT0JGFkuSNBx-XorQ,3131
19
19
  iwa/core/utils.py,sha256=5fc8Ffd3F47iFb8QbnZmKh_d2Fsh1ZytVG2HFnhySEQ,2950
20
- iwa/core/wallet.py,sha256=ZxztWOK8MzIih7nGT52BUvE6Z5a9AA056IV_gqMPQpA,12972
20
+ iwa/core/wallet.py,sha256=sNFK-_0y-EgeLpNHt9o5tCqTM0oVqJra-eAWjR7AgyU,13038
21
21
  iwa/core/chain/__init__.py,sha256=XJMmn0ed-_aVkY2iEMKpuTxPgIKBd41dexSVmEZTa-o,1604
22
22
  iwa/core/chain/errors.py,sha256=9SEbhxZ-qASPkzt-DoI51qq0GRJVqRgqgL720gO7a64,1275
23
- iwa/core/chain/interface.py,sha256=b6Nac4Wg4zygu9B81MTMswt96Ls_--GbPJuEOKu5loY,20497
23
+ iwa/core/chain/interface.py,sha256=GRfWvSPUKdFNrkFD-lR7qFJYbQJs-oE7G_tQMBn4jA0,21097
24
24
  iwa/core/chain/manager.py,sha256=cFEzh6pK5OyVhjhpeMAqhc9RnRDQR1DjIGiGKp-FXBI,1159
25
25
  iwa/core/chain/models.py,sha256=0OgBo08FZEQisOdd00YUMXSAV7BC0CcWpqJ2y-gs0cI,4863
26
26
  iwa/core/chain/rate_limiter.py,sha256=gU7TmWdH9D_wbXKT1X7mIgoIUCWVuebgvRhxiyLGAmI,6613
@@ -36,7 +36,7 @@ iwa/core/services/account.py,sha256=01MoEvl6FJlMnMB4fGwsPtnGa4kgA-d5hJeKu_ACg7Y,
36
36
  iwa/core/services/balance.py,sha256=mPE12CuOFfCaJXaQXWOcQM1O03ZF3ghpy_-oOjNk_GE,4104
37
37
  iwa/core/services/plugin.py,sha256=GNNlbtELyHl7MNVChrypF76GYphxXduxDog4kx1MLi8,3277
38
38
  iwa/core/services/safe.py,sha256=ytNJMndXrzTMHwhDZKYLIh4Q0UTWDBgQgTpof-UqIkA,14827
39
- iwa/core/services/transaction.py,sha256=81jiGF2cxhyy0Oh1jw6uyl0q10oZxOCLnsE3dtOgHJ0,7375
39
+ iwa/core/services/transaction.py,sha256=3IeTLntewa9XevPTMrNhjOUwdv0nMdU3KqlxljjL0Z0,14286
40
40
  iwa/core/services/transfer/__init__.py,sha256=ZJfshFxJRsp8rkOqfVvd1cqEzIJ9tqBJh8pc0l90GLk,5576
41
41
  iwa/core/services/transfer/base.py,sha256=sohz-Ss2i-pGYGl4x9bD93cnYKcSvsXaXyvyRawvgQs,9043
42
42
  iwa/core/services/transfer/erc20.py,sha256=0GvlfETgdJg15azs1apH1gI6Vm3gAv22o1saNbIfiAY,8685
@@ -65,7 +65,7 @@ iwa/plugins/olas/contracts/activity_checker.py,sha256=UDbCgFOyuEhHf1qoUwCUdLc8oK
65
65
  iwa/plugins/olas/contracts/base.py,sha256=y73aQbDq6l4zUpz_eQAg4MsLkTAEqjjupXlcvxjfgCI,240
66
66
  iwa/plugins/olas/contracts/mech.py,sha256=dXYtyORc-oiu9ga5PtTquOFkoakb6BLGKvlUsteygIg,2767
67
67
  iwa/plugins/olas/contracts/mech_marketplace.py,sha256=hMADl5MQGvT2wLRKu4vHGe4RrAZVq8Y2M_EvXWWz528,1554
68
- iwa/plugins/olas/contracts/service.py,sha256=jGCA51qhpVhguRfVPRnfL08WNQBbruvxiCaiispRm3U,6739
68
+ iwa/plugins/olas/contracts/service.py,sha256=BDQKeCTCnBNrwKD1a8rrlLytpKG3CAdjr-s0ec-dsFY,8243
69
69
  iwa/plugins/olas/contracts/staking.py,sha256=vt2UZ6G0edg1EbPrzFK5AIse531bQTu4PLydQ6rgrAA,14494
70
70
  iwa/plugins/olas/contracts/abis/activity_checker.json,sha256=HT0IMbyTLMO71ITBKwoS950rHe772suPP4b8eDAodJ0,2230
71
71
  iwa/plugins/olas/contracts/abis/mech.json,sha256=bMMCXInjE_2PTPnc_sIyS_H8pod5Sm_e-xTbKgZppKc,16369
@@ -73,6 +73,7 @@ iwa/plugins/olas/contracts/abis/mech_marketplace.json,sha256=KPnF-H_UATb3wdb_7o6
73
73
  iwa/plugins/olas/contracts/abis/mech_new.json,sha256=j6HkhTpVQEA4la13Kp1Q_pwlt2x5Ywh7GCEjz4q2_ws,20995
74
74
  iwa/plugins/olas/contracts/abis/service_manager.json,sha256=jsByfx_NPNqHJBbauGEg2S41D0ZYUHa24TzpJQuk604,29735
75
75
  iwa/plugins/olas/contracts/abis/service_registry.json,sha256=phtK1FHUZRtUHP0HeISyO2jlrlzGiETON_Ljd_kLYn4,43864
76
+ iwa/plugins/olas/contracts/abis/service_registry_token_utility.json,sha256=GR02mv9b8yckGubh_Huca_jbczw30AG-34ocZELNLPI,57624
76
77
  iwa/plugins/olas/contracts/abis/staking.json,sha256=_W3NBuygSU-tsqdWTD7P0PmCVz7ZUCqIoJkW60ChjLw,31139
77
78
  iwa/plugins/olas/contracts/abis/staking_token.json,sha256=cuUOmi1s4Z6VSIX0an_IxK6qkPeoyPt3NUdvlX8GlPI,81288
78
79
  iwa/plugins/olas/scripts/test_full_mech_flow.py,sha256=id9IxC06FOKwexgwsG5nbsTB2rQLlIq5a5soMvK0IgY,9021
@@ -80,14 +81,14 @@ iwa/plugins/olas/scripts/test_simple_lifecycle.py,sha256=8T50tOZx3afeECSfCNAb0rA
80
81
  iwa/plugins/olas/service_manager/__init__.py,sha256=GXiThMEY3nPgHUl1i-DLrF4h96z9jPxxI8Jepo2E1PM,1926
81
82
  iwa/plugins/olas/service_manager/base.py,sha256=V4o71ZYUSc_GzM-RWocaAGsrqI-fa5V7CcyloVpcjwE,4666
82
83
  iwa/plugins/olas/service_manager/drain.py,sha256=IS7YYKuQdkULcNdxfHVzjcq95pXKdpajolzLL78u4jc,12430
83
- iwa/plugins/olas/service_manager/lifecycle.py,sha256=0jGLoqNLRuIqzpv2VVtAqVtnuKSwkzhWw8-m8qknjQU,36834
84
+ iwa/plugins/olas/service_manager/lifecycle.py,sha256=DIB6yrP0VPICu6558uQJuFp2sgrA66iVNTzZVUUowGw,47159
84
85
  iwa/plugins/olas/service_manager/mech.py,sha256=72-tEap-aYd0gebcH6y_De1SNeL6OrXn7sWuv_Ok_-Y,12224
85
- iwa/plugins/olas/service_manager/staking.py,sha256=zwI2IREh502DDjhgKDyHr7puXRi46sQ7xp7KgbcZf3w,23931
86
+ iwa/plugins/olas/service_manager/staking.py,sha256=Z9GzlPfY7qSSjc9xPhWvb9qywxu_7OB3Gc1eBli07pY,28058
86
87
  iwa/plugins/olas/tests/conftest.py,sha256=4vM7EI00SrTGyeP0hNzsGSQHEj2-iznVgzlNh2_OGfo,739
87
88
  iwa/plugins/olas/tests/test_importer.py,sha256=i9LKov7kNRECB3hmRnhKBwcfx3uxtjWe4BB77bOOpeo,4282
88
89
  iwa/plugins/olas/tests/test_importer_error_handling.py,sha256=X37TrvJ6-3-NuJ2megm0Cnx3KJdA1wke563pRf_EPJk,12084
89
90
  iwa/plugins/olas/tests/test_mech_contracts.py,sha256=wvxuigPafF-ySIHVBdWVei3AO418iPh7cSVdAlUGm_s,3566
90
- iwa/plugins/olas/tests/test_olas_contracts.py,sha256=V409KPeGQl6wYV8unyiZ381TGahFcPNZxj1zJ40VbAM,10627
91
+ iwa/plugins/olas/tests/test_olas_contracts.py,sha256=B8X-5l1KfYMoZOiM94_rcNzbILLl78rqt_jhyxzAOqE,10835
91
92
  iwa/plugins/olas/tests/test_olas_integration.py,sha256=uIA9NB1iaOSTOaPgY5gRvrFxFLeq6Z93239yi2qzj1g,20488
92
93
  iwa/plugins/olas/tests/test_olas_models.py,sha256=5scX-wvRLGH3G44S2okq_tyQ9Rk7Pd0Ak1zNCZ2HtI4,4957
93
94
  iwa/plugins/olas/tests/test_olas_view.py,sha256=kh3crsriyoRiZC6l8vzGllocvQnYmqziv-csbmXih0E,10489
@@ -95,10 +96,10 @@ iwa/plugins/olas/tests/test_olas_view_actions.py,sha256=jAxr9bjFNAaxGf1btIrxdMaH
95
96
  iwa/plugins/olas/tests/test_olas_view_modals.py,sha256=8j0PNFjKqFC5V1kBdVFWNLMvqGt49H6fLSYGxn02c8o,5562
96
97
  iwa/plugins/olas/tests/test_plugin.py,sha256=RVgU-Cq6t_3mOh90xFAGwlJOV7ZIgp0VNaK5ZAxisAQ,2565
97
98
  iwa/plugins/olas/tests/test_plugin_full.py,sha256=xevLYmdU4zd5FyEEEn9gvzGimPztmt6vymybeZHXnq8,8507
98
- iwa/plugins/olas/tests/test_service_lifecycle.py,sha256=dhIDzgcXh1VV-S6VGXtNqtdxxIdXY1F1hRcPL6RBxno,5649
99
- iwa/plugins/olas/tests/test_service_manager.py,sha256=dsnj1DfSYptIZkiPaLHGM9utbX9XOAy0axuzu-3kofg,41818
100
- iwa/plugins/olas/tests/test_service_manager_errors.py,sha256=BtN-89gwaFpy3RJIDt98U0TT0lksg9NHvoSpSBHSXag,8229
101
- iwa/plugins/olas/tests/test_service_manager_flows.py,sha256=HsAD1axnfow1iTiRBqR7DT6sa3U-q8ApOlYN4Cd87Ao,20142
99
+ iwa/plugins/olas/tests/test_service_lifecycle.py,sha256=sOCtpz8T9s55AZe9AoqP1h3XrXw5NDSjDqwLgYThvU4,5559
100
+ iwa/plugins/olas/tests/test_service_manager.py,sha256=wUdgB_73WtMxzpO3olMCwet9v9EudGr9uQyXeF9o_yE,40380
101
+ iwa/plugins/olas/tests/test_service_manager_errors.py,sha256=M49aZQYVBvPAEvJdpJO6gN8wC1tUdHnln7XxmqO_O50,8151
102
+ iwa/plugins/olas/tests/test_service_manager_flows.py,sha256=lxkXdK2Ht92wAywMUyXYYRfkR3boixzGGF47MEgcq54,19418
102
103
  iwa/plugins/olas/tests/test_service_manager_mech.py,sha256=qG6qu5IPRNypXUsblU2OEkuiuwDJ0TH8RXZbibmTFcQ,4937
103
104
  iwa/plugins/olas/tests/test_service_manager_rewards.py,sha256=hIVckGl5rEr-KHGNUxxVopal0Tpw4EZharBt0MbaCVA,11798
104
105
  iwa/plugins/olas/tests/test_service_manager_validation.py,sha256=ajlfH5uc4mAHf8A7GLE5cW7X8utM2vUilM0JdGDdlVg,5382
@@ -140,8 +141,8 @@ iwa/web/routers/olas/__init__.py,sha256=Jo6Dm1e8fHafCD800fbxsxeFz3tvuEEKXEf5-9tj
140
141
  iwa/web/routers/olas/admin.py,sha256=PMRdNelqYgQ1xbqh3floFV5xrVtBRQiwZPd8J9_ffxg,5785
141
142
  iwa/web/routers/olas/funding.py,sha256=f8fADNtbZEBFl-vuVKfas6os38Vot6K5tJBTenZmCD0,4832
142
143
  iwa/web/routers/olas/general.py,sha256=dPsBQppTGoQY1RztliUhseOHOZGeeCR10lhThD9kyXo,803
143
- iwa/web/routers/olas/services.py,sha256=fq_NBRlXlc-cHpAJYwZ7KsDqgcnB7vSCFqrHZnsLiYQ,14740
144
- iwa/web/routers/olas/staking.py,sha256=3f5flyAb9uDdw6WKH3f68ERA6x_6geJGqOGeTMz-Rbs,12128
144
+ iwa/web/routers/olas/services.py,sha256=IpjvkpJeCwREbdHt47gov-fvTl9bY4EBUmZZZEHi3iI,16310
145
+ iwa/web/routers/olas/staking.py,sha256=N1pMcPjhpfSPi7Sl7XIIAPoFxf0hptdvkUqkTtgqPcc,12424
145
146
  iwa/web/static/app.js,sha256=BCpAp1BcFVcfEfqXa-9gOtjb-8YlV5NIPWgSeCchD1E,113472
146
147
  iwa/web/static/index.html,sha256=q7s7plnMbN1Nkzr5bRxZgvgOFerUChEGIZW7SpAVtPc,28514
147
148
  iwa/web/static/style.css,sha256=aTtE42mmfYV6y7xfo9cUgUhT8x-KyNC1zmPjSdskxIk,24315
@@ -149,7 +150,7 @@ iwa/web/tests/test_web_endpoints.py,sha256=C264MH-CTyDW4GLUrTXBgLJKUk4-89pFAScBd
149
150
  iwa/web/tests/test_web_olas.py,sha256=0CVSsrncOeJ3x0ECV7mVLQV_CXZRrOqGiVjgLIi6hZ8,16308
150
151
  iwa/web/tests/test_web_swap.py,sha256=7A4gBJFL01kIXPtW1E1J17SCsVc_0DmUn-R8kKrnnVA,2974
151
152
  iwa/web/tests/test_web_swap_coverage.py,sha256=zGNrzlhZ_vWDCvWmLcoUwFgqxnrp_ACbo49AtWBS_Kw,5584
152
- iwa-0.0.10.dist-info/licenses/LICENSE,sha256=eIubm_IlBHPYRQlLNZKbBNKhJUUP3JH0A2miZUhAVfI,1078
153
+ iwa-0.0.11.dist-info/licenses/LICENSE,sha256=eIubm_IlBHPYRQlLNZKbBNKhJUUP3JH0A2miZUhAVfI,1078
153
154
  tests/legacy_cow.py,sha256=oOkZvIxL70ReEoD9oHQbOD5GpjIr6AGNHcOCgfPlerU,8389
154
155
  tests/legacy_safe.py,sha256=AssM2g13E74dNGODu_H0Q0y412lgqsrYnEzI97nm_Ts,2972
155
156
  tests/legacy_transaction_retry_logic.py,sha256=D9RqZ7DBu61Xr2djBAodU2p9UE939LL-DnQXswX5iQk,1497
@@ -158,7 +159,7 @@ tests/legacy_wallets_screen.py,sha256=9hZnX-VhKgwH9w8MxbNdboRyNxLDhOakLKJECsw_vh
158
159
  tests/legacy_web.py,sha256=q2ERIriaDHT3Q8axG2N3ucO7f2VSvV_WkuPR00DVko4,8577
159
160
  tests/test_account_service.py,sha256=g_AIVT2jhlvUtbFTaCd-d15x4CmXJQaV66tlAgnaXwY,3745
160
161
  tests/test_balance_service.py,sha256=86iEkPd2M1-UFy3qOxV1EguQOEYbboy2-2mAyS3ctGs,6549
161
- tests/test_chain.py,sha256=uXbNl9wD4e2qV1xs_MO74Soj3iaH-5xoxge4rD3FypU,16986
162
+ tests/test_chain.py,sha256=naDz3WNrB8J3hAcId8of8R4_jN0vEWMC28-70hQEU_s,17240
162
163
  tests/test_chain_interface.py,sha256=Wu0q0sREtmYBp7YvWrBIrrSTtqeQj18oJp2VmMUEMec,8312
163
164
  tests/test_chain_interface_coverage.py,sha256=fvrVvw8-DMwdsSFKQHUhpbfutrVRxnnTc-tjB7Bb-jo,3327
164
165
  tests/test_cli.py,sha256=WW6EDeHLws5-BqFNOy11pH_D5lttuyspD5hrDCFpR0Q,3968
@@ -200,8 +201,8 @@ tests/test_utils.py,sha256=vkP49rYNI8BRzLpWR3WnKdDr8upeZjZcs7Rx0pjbQMo,1292
200
201
  tests/test_workers.py,sha256=MInwdkFY5LdmFB3o1odIaSD7AQZb3263hNafO1De5PE,2793
201
202
  tools/create_and_stake_service.py,sha256=1xwy_bJQI1j9yIQ968Oc9Db_F6mk1659LuuZntTASDE,3742
202
203
  tools/verify_drain.py,sha256=PkMjblyOOAuQge88FwfEzRtCYeEtJxXhPBmtQYCoQ-8,6743
203
- iwa-0.0.10.dist-info/METADATA,sha256=GeRcXbxPd8-PCggPGpiLqM-ovGziAsHJp1SzHWMxMao,7295
204
- iwa-0.0.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
205
- iwa-0.0.10.dist-info/entry_points.txt,sha256=nwB6kscrfA7M00pYmL2j-sBH6eF6h2ga9IK1BZxdiyQ,241
206
- iwa-0.0.10.dist-info/top_level.txt,sha256=kedS9cRUbm4JE2wYeabIXilhHjN8KCw0IGbqqqsw0Bs,16
207
- iwa-0.0.10.dist-info/RECORD,,
204
+ iwa-0.0.11.dist-info/METADATA,sha256=zjnguna0n38HHpQ8UrUvwj4gT8ZZkIp7ivYg0mYax_w,7295
205
+ iwa-0.0.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
206
+ iwa-0.0.11.dist-info/entry_points.txt,sha256=nwB6kscrfA7M00pYmL2j-sBH6eF6h2ga9IK1BZxdiyQ,241
207
+ iwa-0.0.11.dist-info/top_level.txt,sha256=kedS9cRUbm4JE2wYeabIXilhHjN8KCw0IGbqqqsw0Bs,16
208
+ iwa-0.0.11.dist-info/RECORD,,
tests/test_chain.py CHANGED
@@ -340,8 +340,13 @@ def test_chain_interface_with_real_chains():
340
340
  sym = interface.get_token_symbol(valid_addr_1)
341
341
  assert sym == "SYM"
342
342
 
343
- dec = interface.get_token_decimals(valid_addr_1)
344
- assert dec == 18
343
+ # get_token_decimals uses web3.eth.contract directly, not ERC20Contract
344
+ mock_contract = MagicMock()
345
+ mock_contract.functions.decimals.return_value.call.return_value = 18
346
+ interface.web3.eth.contract.return_value = mock_contract
347
+
348
+ dec = interface.get_token_decimals(valid_addr_1)
349
+ assert dec == 18
345
350
 
346
351
 
347
352
  # --- Negative Tests ---
@@ -438,13 +443,13 @@ def test_get_token_decimals_fallback_on_error(mock_web3):
438
443
 
439
444
  ci = ChainInterface(chain)
440
445
 
441
- with patch("iwa.core.contracts.erc20.ERC20Contract") as mock_erc20:
442
- mock_erc20.side_effect = Exception("Contract not found")
446
+ # get_token_decimals uses web3.eth.contract directly, mock it to raise error
447
+ ci.web3.eth.contract.side_effect = Exception("Contract not found")
443
448
 
444
- decimals = ci.get_token_decimals("0x1234567890123456789012345678901234567890")
449
+ decimals = ci.get_token_decimals("0x1234567890123456789012345678901234567890")
445
450
 
446
- # Should return default 18 as fallback
447
- assert decimals == 18
451
+ # Should return default 18 as fallback
452
+ assert decimals == 18
448
453
 
449
454
 
450
455
  def test_is_rate_limit_error_detection(mock_web3):
File without changes