iwa 0.0.13__tar.gz → 0.0.14__tar.gz

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 (214) hide show
  1. {iwa-0.0.13/src/iwa.egg-info → iwa-0.0.14}/PKG-INFO +1 -1
  2. {iwa-0.0.13 → iwa-0.0.14}/pyproject.toml +2 -2
  3. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/interface.py +2 -1
  4. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/contract.py +6 -1
  5. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/utils.py +1 -1
  6. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_staking_integration.py +5 -1
  7. {iwa-0.0.13 → iwa-0.0.14/src/iwa.egg-info}/PKG-INFO +1 -1
  8. {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/SOURCES.txt +1 -0
  9. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_chain.py +4 -4
  10. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_contract.py +5 -4
  11. iwa-0.0.14/src/tests/test_rpc_rotation.py +287 -0
  12. {iwa-0.0.13 → iwa-0.0.14}/LICENSE +0 -0
  13. {iwa-0.0.13 → iwa-0.0.14}/README.md +0 -0
  14. {iwa-0.0.13 → iwa-0.0.14}/setup.cfg +0 -0
  15. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/__init__.py +0 -0
  16. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/__main__.py +0 -0
  17. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/__init__.py +0 -0
  18. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/__init__.py +0 -0
  19. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/errors.py +0 -0
  20. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/manager.py +0 -0
  21. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/models.py +0 -0
  22. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/rate_limiter.py +0 -0
  23. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/cli.py +0 -0
  24. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/constants.py +0 -0
  25. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/__init__.py +0 -0
  26. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/abis/erc20.json +0 -0
  27. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/abis/multisend.json +0 -0
  28. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/abis/multisend_call_only.json +0 -0
  29. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/erc20.py +0 -0
  30. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/multisend.py +0 -0
  31. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/db.py +0 -0
  32. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/ipfs.py +0 -0
  33. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/keys.py +0 -0
  34. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/mnemonic.py +0 -0
  35. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/models.py +0 -0
  36. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/monitor.py +0 -0
  37. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/plugins.py +0 -0
  38. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/pricing.py +0 -0
  39. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/secrets.py +0 -0
  40. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/__init__.py +0 -0
  41. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/account.py +0 -0
  42. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/balance.py +0 -0
  43. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/plugin.py +0 -0
  44. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/safe.py +0 -0
  45. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transaction.py +0 -0
  46. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/__init__.py +0 -0
  47. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/base.py +0 -0
  48. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/erc20.py +0 -0
  49. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/multisend.py +0 -0
  50. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/native.py +0 -0
  51. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/swap.py +0 -0
  52. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/tables.py +0 -0
  53. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/test.py +0 -0
  54. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/tests/test_wallet.py +0 -0
  55. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/types.py +0 -0
  56. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/ui.py +0 -0
  57. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/wallet.py +0 -0
  58. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/__init__.py +0 -0
  59. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/__init__.py +0 -0
  60. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow/__init__.py +0 -0
  61. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow/quotes.py +0 -0
  62. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow/swap.py +0 -0
  63. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow/types.py +0 -0
  64. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow_utils.py +0 -0
  65. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/plugin.py +0 -0
  66. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/safe.py +0 -0
  67. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/tests/test_cow.py +0 -0
  68. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/tests/test_safe.py +0 -0
  69. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/__init__.py +0 -0
  70. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/constants.py +0 -0
  71. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/activity_checker.json +0 -0
  72. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/mech.json +0 -0
  73. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/mech_marketplace.json +0 -0
  74. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/mech_new.json +0 -0
  75. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/service_manager.json +0 -0
  76. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/service_registry.json +0 -0
  77. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/service_registry_token_utility.json +0 -0
  78. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/staking.json +0 -0
  79. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/staking_token.json +0 -0
  80. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/activity_checker.py +0 -0
  81. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/base.py +0 -0
  82. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/mech.py +0 -0
  83. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/mech_marketplace.py +0 -0
  84. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/service.py +0 -0
  85. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/staking.py +0 -0
  86. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/importer.py +0 -0
  87. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/mech_reference.py +0 -0
  88. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/models.py +0 -0
  89. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/plugin.py +0 -0
  90. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/scripts/test_full_mech_flow.py +0 -0
  91. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/scripts/test_simple_lifecycle.py +0 -0
  92. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/__init__.py +0 -0
  93. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/base.py +0 -0
  94. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/drain.py +0 -0
  95. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/lifecycle.py +0 -0
  96. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/mech.py +0 -0
  97. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/staking.py +0 -0
  98. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/conftest.py +0 -0
  99. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_importer.py +0 -0
  100. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_importer_error_handling.py +0 -0
  101. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_mech_contracts.py +0 -0
  102. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_contracts.py +0 -0
  103. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_integration.py +0 -0
  104. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_models.py +0 -0
  105. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_view.py +0 -0
  106. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_view_actions.py +0 -0
  107. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_view_modals.py +0 -0
  108. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_plugin.py +0 -0
  109. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_plugin_full.py +0 -0
  110. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_lifecycle.py +0 -0
  111. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager.py +0 -0
  112. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_errors.py +0 -0
  113. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_flows.py +0 -0
  114. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_mech.py +0 -0
  115. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_rewards.py +0 -0
  116. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_validation.py +0 -0
  117. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_staking.py +0 -0
  118. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_staking_validation.py +0 -0
  119. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tui/__init__.py +0 -0
  120. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tui/olas_view.py +0 -0
  121. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/__init__.py +0 -0
  122. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/check_profile.py +0 -0
  123. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/list_contracts.py +0 -0
  124. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/release.py +0 -0
  125. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/reset_env.py +0 -0
  126. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/reset_tenderly.py +0 -0
  127. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/restore_backup.py +0 -0
  128. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/wallet_check.py +0 -0
  129. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/__init__.py +0 -0
  130. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/app.py +0 -0
  131. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/modals/__init__.py +0 -0
  132. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/modals/base.py +0 -0
  133. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/rpc.py +0 -0
  134. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/screens/__init__.py +0 -0
  135. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/screens/wallets.py +0 -0
  136. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/tests/test_app.py +0 -0
  137. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/tests/test_rpc.py +0 -0
  138. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/tests/test_wallets_refactor.py +0 -0
  139. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/tests/test_widgets.py +0 -0
  140. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/widgets/__init__.py +0 -0
  141. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/widgets/base.py +0 -0
  142. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/workers.py +0 -0
  143. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/dependencies.py +0 -0
  144. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/models.py +0 -0
  145. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/accounts.py +0 -0
  146. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/__init__.py +0 -0
  147. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/admin.py +0 -0
  148. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/funding.py +0 -0
  149. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/general.py +0 -0
  150. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/services.py +0 -0
  151. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/staking.py +0 -0
  152. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/state.py +0 -0
  153. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/swap.py +0 -0
  154. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/transactions.py +0 -0
  155. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/server.py +0 -0
  156. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/static/app.js +0 -0
  157. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/static/index.html +0 -0
  158. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/static/style.css +0 -0
  159. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/tests/test_web_endpoints.py +0 -0
  160. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/tests/test_web_olas.py +0 -0
  161. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/tests/test_web_swap.py +0 -0
  162. {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/tests/test_web_swap_coverage.py +0 -0
  163. {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/dependency_links.txt +0 -0
  164. {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/entry_points.txt +0 -0
  165. {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/requires.txt +0 -0
  166. {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/top_level.txt +0 -0
  167. {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_cow.py +0 -0
  168. {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_safe.py +0 -0
  169. {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_transaction_retry_logic.py +0 -0
  170. {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_tui.py +0 -0
  171. {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_wallets_screen.py +0 -0
  172. {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_web.py +0 -0
  173. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_account_service.py +0 -0
  174. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_balance_service.py +0 -0
  175. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_chain_interface.py +0 -0
  176. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_chain_interface_coverage.py +0 -0
  177. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_cli.py +0 -0
  178. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_db.py +0 -0
  179. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_drain_coverage.py +0 -0
  180. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_erc20.py +0 -0
  181. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_gnosis_plugin.py +0 -0
  182. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_keys.py +0 -0
  183. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_legacy_wallet.py +0 -0
  184. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_main.py +0 -0
  185. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_migration.py +0 -0
  186. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_mnemonic.py +0 -0
  187. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_modals.py +0 -0
  188. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_models.py +0 -0
  189. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_monitor.py +0 -0
  190. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_multisend.py +0 -0
  191. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_plugin_service.py +0 -0
  192. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_pricing.py +0 -0
  193. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_rate_limiter.py +0 -0
  194. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_reset_tenderly.py +0 -0
  195. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_rpc_view.py +0 -0
  196. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_safe_coverage.py +0 -0
  197. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_safe_service.py +0 -0
  198. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_service_manager_integration.py +0 -0
  199. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_service_manager_structure.py +0 -0
  200. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_service_transaction.py +0 -0
  201. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_staking_router.py +0 -0
  202. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_staking_simple.py +0 -0
  203. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_tables.py +0 -0
  204. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transaction_service.py +0 -0
  205. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_multisend.py +0 -0
  206. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_native.py +0 -0
  207. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_security.py +0 -0
  208. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_structure.py +0 -0
  209. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_swap_unit.py +0 -0
  210. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_ui_coverage.py +0 -0
  211. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_utils.py +0 -0
  212. {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_workers.py +0 -0
  213. {iwa-0.0.13 → iwa-0.0.14}/src/tools/create_and_stake_service.py +0 -0
  214. {iwa-0.0.13 → iwa-0.0.14}/src/tools/verify_drain.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iwa
3
- Version: 0.0.13
3
+ Version: 0.0.14
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,6 +1,6 @@
1
1
  [project]
2
2
  name = "iwa"
3
- version = "0.0.13"
3
+ version = "0.0.14"
4
4
  description = "A secure, modular, and plugin-based framework for crypto agents and ops"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12,<4.0"
@@ -71,7 +71,7 @@ where = ["src"]
71
71
 
72
72
  [tool.ruff]
73
73
  line-length = 100
74
- target-version = "0.0.13"
74
+ target-version = "0.0.14"
75
75
  fix = true
76
76
 
77
77
  [tool.ruff.lint]
@@ -379,7 +379,8 @@ class ChainInterface:
379
379
  """
380
380
  try:
381
381
  # Call decimals() directly without with_retry to avoid error logging
382
- contract = self.web3.eth.contract(
382
+ # Use _web3 directly to ensure current provider after RPC rotation
383
+ contract = self.web3._web3.eth.contract(
383
384
  address=self.web3.to_checksum_address(address),
384
385
  abi=[{"constant": True, "inputs": [], "name": "decimals", "outputs": [{"type": "uint8"}], "type": "function"}]
385
386
  )
@@ -63,10 +63,15 @@ class ContractInstance:
63
63
 
64
64
  This property ensures that after an RPC rotation, contract calls
65
65
  use the updated provider instead of the original one.
66
+
67
+ Note: We use _web3 directly (not the RateLimitedWeb3 wrapper) to ensure
68
+ the contract is bound to the current provider. The wrapper's set_backend()
69
+ updates _web3, but contracts created via the wrapper may cache old providers.
66
70
  """
67
71
  # Always create a fresh contract to use the current Web3 provider
68
72
  # This is necessary because RPC rotation changes the underlying provider
69
- return self.chain_interface.web3.eth.contract(address=self.address, abi=self.abi)
73
+ # Access _web3 directly to ensure we get the current provider
74
+ return self.chain_interface.web3._web3.eth.contract(address=self.address, abi=self.abi)
70
75
 
71
76
  def load_error_selectors(self) -> Dict[str, Any]:
72
77
  """Load error selectors from the contract ABI."""
@@ -87,7 +87,7 @@ def configure_logger():
87
87
 
88
88
  def get_version(package_name: str) -> str:
89
89
  """Get package version."""
90
- from importlib.metadata import version, PackageNotFoundError
90
+ from importlib.metadata import PackageNotFoundError, version
91
91
  try:
92
92
  return version(package_name)
93
93
  except PackageNotFoundError:
@@ -194,9 +194,10 @@ def test_staking_contract(tmp_path): # noqa: C901
194
194
  mock_chain = MagicMock()
195
195
  mock_interfaces.return_value.get.return_value = mock_chain
196
196
 
197
- # Mock web3
197
+ # Mock web3 - use _web3 since contract.py now accesses _web3 directly
198
198
  mock_web3 = MagicMock()
199
199
  mock_chain.web3 = mock_web3
200
+ mock_chain.web3._web3 = mock_web3 # For RPC rotation fix
200
201
 
201
202
  # Mock contract factory
202
203
  mock_contract = MagicMock()
@@ -252,6 +253,9 @@ def test_staking_contract(tmp_path): # noqa: C901
252
253
 
253
254
  staking.ts_checkpoint = MagicMock(return_value=0)
254
255
 
256
+ # Mock get_required_requests to return an int (not MagicMock)
257
+ staking.get_required_requests = MagicMock(return_value=2)
258
+
255
259
  # Trigger original_open hit
256
260
  try:
257
261
  test_file = tmp_path / "test_lookup.txt"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iwa
3
- Version: 0.0.13
3
+ Version: 0.0.14
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
@@ -189,6 +189,7 @@ src/tests/test_plugin_service.py
189
189
  src/tests/test_pricing.py
190
190
  src/tests/test_rate_limiter.py
191
191
  src/tests/test_reset_tenderly.py
192
+ src/tests/test_rpc_rotation.py
192
193
  src/tests/test_rpc_view.py
193
194
  src/tests/test_safe_coverage.py
194
195
  src/tests/test_safe_service.py
@@ -340,10 +340,10 @@ 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
- # get_token_decimals uses web3.eth.contract directly, not ERC20Contract
343
+ # get_token_decimals uses web3._web3.eth.contract directly
344
344
  mock_contract = MagicMock()
345
345
  mock_contract.functions.decimals.return_value.call.return_value = 18
346
- interface.web3.eth.contract.return_value = mock_contract
346
+ interface.web3._web3.eth.contract.return_value = mock_contract
347
347
 
348
348
  dec = interface.get_token_decimals(valid_addr_1)
349
349
  assert dec == 18
@@ -443,8 +443,8 @@ def test_get_token_decimals_fallback_on_error(mock_web3):
443
443
 
444
444
  ci = ChainInterface(chain)
445
445
 
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")
446
+ # get_token_decimals uses web3._web3.eth.contract directly
447
+ ci.web3._web3.eth.contract.side_effect = Exception("Contract not found")
448
448
 
449
449
  decimals = ci.get_token_decimals("0x1234567890123456789012345678901234567890")
450
450
 
@@ -11,7 +11,8 @@ from iwa.core.contracts.contract import ContractInstance
11
11
  def mock_chain_interface():
12
12
  with patch("iwa.core.contracts.contract.ChainInterfaces") as mock:
13
13
  mock_ci = mock.return_value.get.return_value
14
- mock_ci.web3.eth.contract.return_value = MagicMock()
14
+ # contract.py now uses web3._web3.eth.contract directly for RPC rotation compatibility
15
+ mock_ci.web3._web3.eth.contract.return_value = MagicMock()
15
16
  yield mock_ci
16
17
 
17
18
 
@@ -226,7 +227,7 @@ def test_call_reevaluates_contract_on_retry(mock_chain_interface, mock_abi_file)
226
227
  mock.functions.testFunc.return_value.call.return_value = "success"
227
228
  return mock
228
229
 
229
- mock_chain_interface.web3.eth.contract.side_effect = counting_contract_factory
230
+ mock_chain_interface.web3._web3.eth.contract.side_effect = counting_contract_factory
230
231
 
231
232
  # Implement with_retry that actually retries on 429
232
233
  def real_with_retry(fn, max_retries=6, operation_name="operation"):
@@ -274,7 +275,7 @@ def test_call_uses_fresh_provider_after_rotation(mock_chain_interface, mock_abi_
274
275
  provider_versions.append(current_provider_version[0])
275
276
  return mock
276
277
 
277
- mock_chain_interface.web3.eth.contract.side_effect = mock_contract_factory
278
+ mock_chain_interface.web3._web3.eth.contract.side_effect = mock_contract_factory
278
279
 
279
280
  # Simulate RPC rotation by incrementing provider version
280
281
  def simulate_rotation():
@@ -335,7 +336,7 @@ def test_call_with_429_triggers_retry_with_new_contract(mock_chain_interface, mo
335
336
  contract_call_count[0] += 1
336
337
  return result
337
338
 
338
- mock_chain_interface.web3.eth.contract.side_effect = mock_contract_factory
339
+ mock_chain_interface.web3._web3.eth.contract.side_effect = mock_contract_factory
339
340
 
340
341
  # Implement with_retry that actually retries
341
342
  def real_with_retry(fn, max_retries=6, operation_name="operation"):
@@ -0,0 +1,287 @@
1
+ """Comprehensive RPC rotation tests.
2
+
3
+ These tests verify that RPC rotation works correctly when rate limit errors occur,
4
+ ensuring that after rotation, requests actually go to the new RPC.
5
+ """
6
+
7
+ from unittest.mock import MagicMock, PropertyMock, patch
8
+
9
+ import pytest
10
+
11
+ from iwa.core.chain import ChainInterface, SupportedChain
12
+
13
+
14
+ class MockHTTPError(Exception):
15
+ """Mock HTTP 429 error with URL info."""
16
+
17
+ def __init__(self, url: str):
18
+ self.url = url
19
+ super().__init__(f"429 Client Error: Too Many Requests for url: {url}")
20
+
21
+
22
+ @pytest.fixture
23
+ def multi_rpc_chain():
24
+ """Create a chain with multiple RPCs for testing rotation."""
25
+ chain = MagicMock(spec=SupportedChain)
26
+ chain.name = "TestChain"
27
+ chain.rpcs = [
28
+ "https://rpc1.example.com",
29
+ "https://rpc2.example.com",
30
+ "https://rpc3.example.com",
31
+ "https://rpc4.example.com",
32
+ "https://rpc5.example.com",
33
+ ]
34
+ chain.chain_id = 1
35
+ chain.native_currency = "ETH"
36
+ chain.tokens = {}
37
+ type(chain).rpc = PropertyMock(return_value=chain.rpcs[0])
38
+ return chain
39
+
40
+
41
+ @pytest.fixture
42
+ def mock_web3_factory():
43
+ """Factory to create mock Web3 instances that track their RPC URL."""
44
+
45
+ def create_mock_web3(rpc_url: str):
46
+ mock = MagicMock()
47
+ mock.provider.endpoint_uri = rpc_url
48
+ mock.eth.block_number = 12345
49
+ return mock
50
+
51
+ return create_mock_web3
52
+
53
+
54
+ def test_rpc_rotation_basic(multi_rpc_chain):
55
+ """Test that RPC rotation cycles through all available RPCs."""
56
+ with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
57
+ ci = ChainInterface(multi_rpc_chain)
58
+
59
+ # Should start at index 0
60
+ assert ci._current_rpc_index == 0
61
+
62
+ # Rotate through all RPCs
63
+ for expected_index in [1, 2, 3, 4, 0, 1]: # Wraps around
64
+ result = ci.rotate_rpc()
65
+ assert result is True
66
+ assert ci._current_rpc_index == expected_index
67
+
68
+
69
+ def test_rpc_rotation_updates_provider():
70
+ """Test that after rotation, set_backend is called to update the provider.
71
+
72
+ The current implementation uses set_backend() to hot-swap the underlying
73
+ Web3 instance rather than creating a new RateLimitedWeb3 wrapper.
74
+ """
75
+ chain = MagicMock(spec=SupportedChain)
76
+ chain.name = "TestChain"
77
+ chain.rpcs = ["https://rpc1.example.com", "https://rpc2.example.com"]
78
+ type(chain).rpc = PropertyMock(return_value=chain.rpcs[0])
79
+
80
+ set_backend_calls = []
81
+
82
+ class MockRateLimitedWeb3:
83
+ def __init__(self, w3, rl, ci):
84
+ self._web3 = w3
85
+ self.set_backend = MagicMock(side_effect=lambda new_w3: set_backend_calls.append(new_w3))
86
+
87
+ def __getattr__(self, name):
88
+ return getattr(self._web3, name)
89
+
90
+ with patch("iwa.core.chain.interface.Web3") as mock_web3_class:
91
+ with patch("iwa.core.chain.interface.RateLimitedWeb3", MockRateLimitedWeb3):
92
+ # Make Web3 return a mock with the correct provider URL
93
+ def create_web3_mock(provider):
94
+ mock = MagicMock()
95
+ mock.provider = provider
96
+ return mock
97
+
98
+ mock_web3_class.side_effect = create_web3_mock
99
+ mock_web3_class.HTTPProvider = lambda url, **kwargs: MagicMock(endpoint_uri=url)
100
+
101
+ ci = ChainInterface(chain)
102
+
103
+ # Initially no set_backend calls
104
+ assert len(set_backend_calls) == 0
105
+
106
+ # Rotate
107
+ ci.rotate_rpc()
108
+
109
+ # After rotation, set_backend should have been called
110
+ assert len(set_backend_calls) == 1
111
+ # And it should have been called with a new Web3 instance
112
+ assert set_backend_calls[0].provider.endpoint_uri == "https://rpc2.example.com"
113
+
114
+
115
+ def test_rate_limit_triggers_rotation(multi_rpc_chain):
116
+ """Test that a 429 rate limit error triggers RPC rotation."""
117
+ with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
118
+ ci = ChainInterface(multi_rpc_chain)
119
+
120
+ initial_index = ci._current_rpc_index
121
+ assert initial_index == 0
122
+
123
+ # Simulate a rate limit error
124
+ error = MockHTTPError("https://rpc1.example.com")
125
+ result = ci._handle_rpc_error(error)
126
+
127
+ # Should have detected rate limit and rotated
128
+ assert result["is_rate_limit"] is True
129
+ assert result["rotated"] is True
130
+ assert result["should_retry"] is True
131
+ assert ci._current_rpc_index == 1
132
+
133
+
134
+ def test_with_retry_rotates_on_rate_limit(multi_rpc_chain):
135
+ """Test that with_retry properly rotates RPC on rate limit and succeeds on new RPC."""
136
+ with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
137
+ ci = ChainInterface(multi_rpc_chain)
138
+
139
+ call_count = 0
140
+ rpc_indices_seen = []
141
+
142
+ def flaky_operation():
143
+ nonlocal call_count
144
+ call_count += 1
145
+ rpc_indices_seen.append(ci._current_rpc_index)
146
+
147
+ # Fail on first RPC, succeed on second
148
+ if ci._current_rpc_index == 0:
149
+ raise MockHTTPError(ci.chain.rpcs[0])
150
+ return "success"
151
+
152
+ with patch("time.sleep"): # Skip actual delays
153
+ result = ci.with_retry(flaky_operation, operation_name="test_operation")
154
+
155
+ assert result == "success"
156
+ assert 0 in rpc_indices_seen # Started on RPC 0
157
+ assert 1 in rpc_indices_seen # Rotated to RPC 1
158
+ assert ci._current_rpc_index == 1 # Ended on RPC 1
159
+
160
+
161
+ def test_with_retry_exhausts_all_rpcs_then_backs_off(multi_rpc_chain):
162
+ """Test that when all RPCs fail, we trigger backoff."""
163
+ with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
164
+ ci = ChainInterface(multi_rpc_chain)
165
+
166
+ # All RPCs fail
167
+ def always_fail():
168
+ raise MockHTTPError(ci.chain.rpcs[ci._current_rpc_index])
169
+
170
+ with patch("time.sleep"):
171
+ with pytest.raises(MockHTTPError):
172
+ ci.with_retry(always_fail, max_retries=6, operation_name="doomed_operation")
173
+
174
+ # Should have rotated through multiple RPCs
175
+ assert ci._current_rpc_index > 0
176
+
177
+
178
+ def test_rotation_applies_to_subsequent_calls():
179
+ """Test that after rotation, subsequent method calls use the new RPC.
180
+
181
+ This is the critical test - verifying that the fix for the RPC rotation
182
+ bug actually works. After rotation, calls should go to the new RPC.
183
+ """
184
+ chain = MagicMock(spec=SupportedChain)
185
+ chain.name = "TestChain"
186
+ chain.rpcs = ["https://rpc1.example.com", "https://rpc2.example.com"]
187
+ type(chain).rpc = PropertyMock(return_value=chain.rpcs[0])
188
+
189
+ with patch("iwa.core.chain.interface.Web3") as mock_web3_class:
190
+ # Track which provider is being used for each call
191
+ current_provider_url = ["https://rpc1.example.com"]
192
+
193
+ def create_web3(provider):
194
+ mock = MagicMock()
195
+ mock.provider = provider
196
+
197
+ # eth.get_balance should use the current provider
198
+ def mock_get_balance(addr):
199
+ return f"balance_from_{current_provider_url[0]}"
200
+
201
+ mock.eth.get_balance = mock_get_balance
202
+ mock.eth.block_number = 12345
203
+ return mock
204
+
205
+ def create_provider(url, **kwargs):
206
+ prov = MagicMock()
207
+ prov.endpoint_uri = url
208
+ current_provider_url[0] = url
209
+ return prov
210
+
211
+ mock_web3_class.side_effect = create_web3
212
+ mock_web3_class.HTTPProvider = create_provider
213
+
214
+ with patch(
215
+ "iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3
216
+ ):
217
+ ci = ChainInterface(chain)
218
+
219
+ # First call uses RPC 1
220
+ result1 = ci.web3.eth.get_balance("0xtest")
221
+ assert "rpc1" in result1
222
+
223
+ # Rotate to RPC 2
224
+ ci.rotate_rpc()
225
+
226
+ # Second call should use RPC 2
227
+ result2 = ci.web3.eth.get_balance("0xtest")
228
+ assert "rpc2" in result2
229
+
230
+
231
+ def test_contract_uses_current_provider_after_rotation():
232
+ """Test that ContractInstance.contract property recreates contract each time.
233
+
234
+ This verifies the contract property doesn't cache and always
235
+ uses the current provider.
236
+ """
237
+ # This is a simplified test that verifies the contract property
238
+ # creates a new contract each time it's accessed
239
+ from pathlib import Path
240
+
241
+ from iwa.core.contracts.contract import ContractInstance
242
+
243
+ # Mock a minimal chain interface
244
+ mock_web3 = MagicMock()
245
+ mock_web3._web3.eth.contract = MagicMock()
246
+
247
+ mock_chain_interface = MagicMock()
248
+ mock_chain_interface.web3 = mock_web3
249
+
250
+ # Create a ContractInstance with mocked dependencies
251
+ with patch("iwa.core.chain.ChainInterfaces") as mock_interfaces:
252
+ mock_interfaces.return_value.get.return_value = mock_chain_interface
253
+
254
+ # Mock the ABI loading
255
+ mock_abi = [{"type": "function", "name": "test", "inputs": [], "outputs": []}]
256
+
257
+ with patch("builtins.open", MagicMock()):
258
+ with patch("json.load", return_value=mock_abi):
259
+ # Need to mock abi_path for ContractInstance
260
+ with patch.object(ContractInstance, "abi_path", Path("/fake/path.json")):
261
+ with patch.object(ContractInstance, "load_error_selectors", return_value={}):
262
+ instance = ContractInstance.__new__(ContractInstance)
263
+ instance.address = "0x1234567890123456789012345678901234567890"
264
+ instance.abi = mock_abi
265
+ instance.chain_interface = mock_chain_interface
266
+ instance._contract_cache = None
267
+ instance.error_selectors = {}
268
+
269
+ # Access contract property twice
270
+ # The key test: verify it calls web3._web3.eth.contract each time
271
+ _ = instance.contract
272
+ _ = instance.contract
273
+
274
+ # Should have called contract() twice (no caching)
275
+ assert mock_web3._web3.eth.contract.call_count == 2
276
+
277
+
278
+ def test_single_rpc_no_rotation(multi_rpc_chain):
279
+ """Test that rotation returns False when there's only one RPC."""
280
+ multi_rpc_chain.rpcs = ["https://only-one.example.com"]
281
+
282
+ with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
283
+ ci = ChainInterface(multi_rpc_chain)
284
+
285
+ result = ci.rotate_rpc()
286
+ assert result is False
287
+ assert ci._current_rpc_index == 0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes