iwa 0.0.1a2__tar.gz → 0.0.1a4__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 (215) hide show
  1. {iwa-0.0.1a2/src/iwa.egg-info → iwa-0.0.1a4}/PKG-INFO +6 -3
  2. {iwa-0.0.1a2 → iwa-0.0.1a4}/README.md +2 -1
  3. {iwa-0.0.1a2 → iwa-0.0.1a4}/pyproject.toml +15 -3
  4. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/chain/interface.py +51 -61
  5. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/chain/models.py +7 -7
  6. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/chain/rate_limiter.py +21 -10
  7. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/cli.py +27 -2
  8. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/constants.py +6 -5
  9. iwa-0.0.1a4/src/iwa/core/contracts/abis/erc20.json +930 -0
  10. iwa-0.0.1a4/src/iwa/core/contracts/abis/multisend.json +24 -0
  11. iwa-0.0.1a4/src/iwa/core/contracts/abis/multisend_call_only.json +17 -0
  12. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/contracts/contract.py +16 -4
  13. iwa-0.0.1a4/src/iwa/core/ipfs.py +149 -0
  14. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/keys.py +259 -29
  15. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/mnemonic.py +3 -13
  16. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/models.py +28 -6
  17. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/pricing.py +4 -4
  18. iwa-0.0.1a4/src/iwa/core/secrets.py +77 -0
  19. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/safe.py +3 -3
  20. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/utils.py +6 -1
  21. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/wallet.py +4 -0
  22. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/safe.py +2 -2
  23. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/tests/test_safe.py +1 -1
  24. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/constants.py +8 -0
  25. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/abis/activity_checker.json +110 -0
  26. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/abis/mech.json +740 -0
  27. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/abis/mech_marketplace.json +1293 -0
  28. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/abis/mech_new.json +954 -0
  29. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/abis/service_manager.json +1382 -0
  30. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/abis/service_registry.json +1909 -0
  31. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/abis/staking.json +1400 -0
  32. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/abis/staking_token.json +1274 -0
  33. iwa-0.0.1a4/src/iwa/plugins/olas/contracts/mech.py +77 -0
  34. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/plugin.py +2 -2
  35. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_plugin_full.py +3 -3
  36. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_staking_integration.py +2 -2
  37. iwa-0.0.1a4/src/iwa/tools/__init__.py +1 -0
  38. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tools/check_profile.py +6 -5
  39. iwa-0.0.1a4/src/iwa/tools/list_contracts.py +136 -0
  40. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tools/release.py +9 -3
  41. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tools/reset_env.py +2 -2
  42. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tools/reset_tenderly.py +26 -24
  43. iwa-0.0.1a4/src/iwa/tools/wallet_check.py +150 -0
  44. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/dependencies.py +4 -4
  45. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/state.py +1 -0
  46. iwa-0.0.1a4/src/iwa/web/static/app.js +3096 -0
  47. iwa-0.0.1a4/src/iwa/web/static/index.html +543 -0
  48. iwa-0.0.1a4/src/iwa/web/static/style.css +1443 -0
  49. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/tests/test_web_endpoints.py +3 -2
  50. iwa-0.0.1a4/src/iwa/web/tests/test_web_swap_coverage.py +156 -0
  51. {iwa-0.0.1a2 → iwa-0.0.1a4/src/iwa.egg-info}/PKG-INFO +6 -3
  52. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa.egg-info/SOURCES.txt +22 -2
  53. iwa-0.0.1a4/src/iwa.egg-info/entry_points.txt +6 -0
  54. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa.egg-info/requires.txt +2 -0
  55. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa.egg-info/top_level.txt +0 -1
  56. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_chain.py +1 -1
  57. iwa-0.0.1a4/src/tests/test_chain_interface_coverage.py +92 -0
  58. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_contract.py +2 -0
  59. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_keys.py +58 -15
  60. iwa-0.0.1a4/src/tests/test_migration.py +52 -0
  61. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_mnemonic.py +1 -1
  62. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_pricing.py +7 -7
  63. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_safe_coverage.py +1 -1
  64. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_safe_service.py +3 -3
  65. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_staking_router.py +13 -1
  66. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tools/verify_drain.py +1 -1
  67. iwa-0.0.1a2/src/conftest.py +0 -22
  68. iwa-0.0.1a2/src/iwa/core/settings.py +0 -95
  69. iwa-0.0.1a2/src/iwa/plugins/olas/contracts/mech.py +0 -49
  70. iwa-0.0.1a2/src/iwa.egg-info/entry_points.txt +0 -2
  71. {iwa-0.0.1a2 → iwa-0.0.1a4}/LICENSE +0 -0
  72. {iwa-0.0.1a2 → iwa-0.0.1a4}/setup.cfg +0 -0
  73. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/__init__.py +0 -0
  74. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/__main__.py +0 -0
  75. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/__init__.py +0 -0
  76. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/chain/__init__.py +0 -0
  77. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/chain/errors.py +0 -0
  78. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/chain/manager.py +0 -0
  79. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/contracts/__init__.py +0 -0
  80. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/contracts/erc20.py +0 -0
  81. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/contracts/multisend.py +0 -0
  82. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/db.py +0 -0
  83. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/monitor.py +0 -0
  84. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/plugins.py +0 -0
  85. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/__init__.py +0 -0
  86. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/account.py +0 -0
  87. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/balance.py +0 -0
  88. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/plugin.py +0 -0
  89. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/transaction.py +0 -0
  90. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/transfer/__init__.py +0 -0
  91. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/transfer/base.py +0 -0
  92. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/transfer/erc20.py +0 -0
  93. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/transfer/multisend.py +0 -0
  94. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/transfer/native.py +0 -0
  95. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/services/transfer/swap.py +0 -0
  96. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/tables.py +0 -0
  97. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/test.py +0 -0
  98. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/tests/test_wallet.py +0 -0
  99. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/types.py +0 -0
  100. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/core/ui.py +0 -0
  101. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/__init__.py +0 -0
  102. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/__init__.py +0 -0
  103. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/cow/__init__.py +0 -0
  104. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/cow/quotes.py +0 -0
  105. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/cow/swap.py +0 -0
  106. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/cow/types.py +0 -0
  107. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/cow_utils.py +0 -0
  108. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/plugin.py +0 -0
  109. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/gnosis/tests/test_cow.py +0 -0
  110. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/__init__.py +0 -0
  111. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/contracts/activity_checker.py +0 -0
  112. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/contracts/base.py +0 -0
  113. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/contracts/mech_marketplace.py +0 -0
  114. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/contracts/service.py +0 -0
  115. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/contracts/staking.py +0 -0
  116. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/importer.py +0 -0
  117. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/mech_reference.py +0 -0
  118. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/models.py +0 -0
  119. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/scripts/test_full_mech_flow.py +0 -0
  120. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/scripts/test_simple_lifecycle.py +0 -0
  121. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/service_manager/__init__.py +0 -0
  122. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/service_manager/base.py +0 -0
  123. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/service_manager/drain.py +0 -0
  124. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/service_manager/lifecycle.py +0 -0
  125. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/service_manager/mech.py +0 -0
  126. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/service_manager/staking.py +0 -0
  127. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/conftest.py +0 -0
  128. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_importer.py +0 -0
  129. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_importer_error_handling.py +0 -0
  130. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_mech_contracts.py +0 -0
  131. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_olas_contracts.py +0 -0
  132. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_olas_integration.py +0 -0
  133. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_olas_models.py +0 -0
  134. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_olas_view.py +0 -0
  135. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_olas_view_actions.py +0 -0
  136. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_olas_view_modals.py +0 -0
  137. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_plugin.py +0 -0
  138. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_service_lifecycle.py +0 -0
  139. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_service_manager.py +0 -0
  140. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_service_manager_errors.py +0 -0
  141. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_service_manager_flows.py +0 -0
  142. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_service_manager_mech.py +0 -0
  143. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_service_manager_rewards.py +0 -0
  144. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_service_manager_validation.py +0 -0
  145. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_service_staking.py +0 -0
  146. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tests/test_staking_validation.py +0 -0
  147. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tui/__init__.py +0 -0
  148. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/plugins/olas/tui/olas_view.py +0 -0
  149. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tools/restore_backup.py +0 -0
  150. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/__init__.py +0 -0
  151. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/app.py +0 -0
  152. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/modals/__init__.py +0 -0
  153. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/modals/base.py +0 -0
  154. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/rpc.py +0 -0
  155. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/screens/__init__.py +0 -0
  156. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/screens/wallets.py +0 -0
  157. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/tests/test_app.py +0 -0
  158. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/tests/test_rpc.py +0 -0
  159. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/tests/test_wallets_refactor.py +0 -0
  160. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/tests/test_widgets.py +0 -0
  161. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/widgets/__init__.py +0 -0
  162. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/widgets/base.py +0 -0
  163. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/tui/workers.py +0 -0
  164. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/models.py +0 -0
  165. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/accounts.py +0 -0
  166. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/olas/__init__.py +0 -0
  167. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/olas/admin.py +0 -0
  168. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/olas/funding.py +0 -0
  169. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/olas/general.py +0 -0
  170. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/olas/services.py +0 -0
  171. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/olas/staking.py +0 -0
  172. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/swap.py +0 -0
  173. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/routers/transactions.py +0 -0
  174. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/server.py +0 -0
  175. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/tests/test_web_olas.py +0 -0
  176. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa/web/tests/test_web_swap.py +0 -0
  177. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/iwa.egg-info/dependency_links.txt +0 -0
  178. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/legacy_cow.py +0 -0
  179. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/legacy_safe.py +0 -0
  180. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/legacy_transaction_retry_logic.py +0 -0
  181. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/legacy_tui.py +0 -0
  182. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/legacy_wallets_screen.py +0 -0
  183. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/legacy_web.py +0 -0
  184. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_account_service.py +0 -0
  185. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_balance_service.py +0 -0
  186. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_chain_interface.py +0 -0
  187. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_cli.py +0 -0
  188. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_db.py +0 -0
  189. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_drain_coverage.py +0 -0
  190. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_erc20.py +0 -0
  191. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_gnosis_plugin.py +0 -0
  192. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_legacy_wallet.py +0 -0
  193. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_main.py +0 -0
  194. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_modals.py +0 -0
  195. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_models.py +0 -0
  196. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_monitor.py +0 -0
  197. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_multisend.py +0 -0
  198. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_plugin_service.py +0 -0
  199. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_rate_limiter.py +0 -0
  200. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_reset_tenderly.py +0 -0
  201. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_rpc_view.py +0 -0
  202. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_service_manager_integration.py +0 -0
  203. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_service_manager_structure.py +0 -0
  204. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_service_transaction.py +0 -0
  205. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_staking_simple.py +0 -0
  206. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_tables.py +0 -0
  207. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_transaction_service.py +0 -0
  208. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_transfer_multisend.py +0 -0
  209. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_transfer_native.py +0 -0
  210. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_transfer_security.py +0 -0
  211. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_transfer_structure.py +0 -0
  212. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_transfer_swap_unit.py +0 -0
  213. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_ui_coverage.py +0 -0
  214. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_utils.py +0 -0
  215. {iwa-0.0.1a2 → iwa-0.0.1a4}/src/tests/test_workers.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iwa
3
- Version: 0.0.1a2
4
- Summary: Add your description here
3
+ Version: 0.0.1a4
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
7
7
  License-File: LICENSE
@@ -33,6 +33,8 @@ Requires-Dist: nest-asyncio>=1.6.0
33
33
  Requires-Dist: aiohttp>=3.13.3
34
34
  Requires-Dist: pynacl>=1.6.2
35
35
  Requires-Dist: urllib3>=2.6.3
36
+ Requires-Dist: multiformats>=0.3.1
37
+ Requires-Dist: requests>=2.32.0
36
38
  Dynamic: license-file
37
39
 
38
40
  # Iwa
@@ -160,7 +162,8 @@ just test
160
162
  ### Security Checks
161
163
 
162
164
  ```bash
163
- just security # Runs gitleaks, bandit, and pip-audit
165
+ just security # Runs gitleaks, bandit, and pip-audit
166
+ just wallet-check # Verifies password, keys, and mnemonic integrity
164
167
  ```
165
168
 
166
169
  ### Docker
@@ -123,7 +123,8 @@ just test
123
123
  ### Security Checks
124
124
 
125
125
  ```bash
126
- just security # Runs gitleaks, bandit, and pip-audit
126
+ just security # Runs gitleaks, bandit, and pip-audit
127
+ just wallet-check # Verifies password, keys, and mnemonic integrity
127
128
  ```
128
129
 
129
130
  ### Docker
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "iwa"
3
- version = "0.0.1-alpha2"
4
- description = "Add your description here"
3
+ version = "0.0.1a4"
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"
7
7
  dependencies = [
@@ -33,10 +33,16 @@ dependencies = [
33
33
  "aiohttp>=3.13.3",
34
34
  "pynacl>=1.6.2",
35
35
  "urllib3>=2.6.3",
36
+ "multiformats>=0.3.1",
37
+ "requests>=2.32.0",
36
38
  ]
37
39
 
38
40
  [project.scripts]
39
41
  iwa = "iwa.core.cli:iwa_cli"
42
+ iwa-wallet-check = "iwa.tools.wallet_check:check_wallet"
43
+ iwa-reset-tenderly = "iwa.tools.reset_tenderly:main"
44
+ iwa-reset-env = "iwa.tools.reset_env:main"
45
+ iwa-check-profile = "iwa.tools.check_profile:main"
40
46
 
41
47
  [dependency-groups]
42
48
  dev = [
@@ -57,9 +63,15 @@ dev = [
57
63
  requires = ["setuptools>=61.0", "wheel"]
58
64
  build-backend = "setuptools.build_meta"
59
65
 
66
+ [tool.setuptools.packages.find]
67
+ where = ["src"]
68
+
69
+ [tool.setuptools.package-data]
70
+ "*" = ["*.json", "*.yaml", "*.yml", "*.html", "*.css", "*.js"]
71
+
60
72
  [tool.ruff]
61
73
  line-length = 100
62
- target-version = "0.0.1-alpha2"
74
+ target-version = "0.0.1a4"
63
75
  fix = true
64
76
 
65
77
  [tool.ruff.lint]
@@ -21,8 +21,8 @@ DEFAULT_RPC_TIMEOUT = 10
21
21
  class ChainInterface:
22
22
  """ChainInterface with rate limiting, retry logic, and RPC rotation support."""
23
23
 
24
- DEFAULT_MAX_RETRIES = 3
25
- DEFAULT_RETRY_DELAY = 0.5
24
+ DEFAULT_MAX_RETRIES = 6 # Allow trying most/all available RPCs on rate limit
25
+ DEFAULT_RETRY_DELAY = 1.0 # Base delay between retries (exponential backoff)
26
26
 
27
27
  chain: SupportedChain
28
28
 
@@ -54,42 +54,40 @@ class ChainInterface:
54
54
  return "tenderly" in rpc.lower() or "virtual" in rpc.lower()
55
55
 
56
56
  def init_block_tracking(self):
57
- """Initialize block tracking for limit detection."""
57
+ """Initialize block tracking for limit detection.
58
+
59
+ Only enables block limit warnings if we have a valid tenderly config file
60
+ with initial_block set. Otherwise, leaves _initial_block at 0 which
61
+ disables the warnings (since we can't accurately track usage without
62
+ knowing the fork point).
63
+ """
64
+ if not self.is_tenderly:
65
+ return # Only track for Tenderly vNets
66
+
58
67
  try:
59
- self._initial_block = self.web3.eth.block_number
60
-
61
- if self.is_tenderly:
62
- try:
63
- from iwa.core.constants import get_tenderly_config_path
64
- from iwa.core.models import TenderlyConfig
65
- from iwa.core.settings import settings
66
-
67
- profile = settings.tenderly_profile
68
- config_path = get_tenderly_config_path(profile)
69
-
70
- if config_path.exists():
71
- t_config = TenderlyConfig.load(config_path)
72
- vnet = t_config.vnets.get(self.chain.name)
73
- if not vnet:
74
- vnet = t_config.vnets.get(self.chain.name.lower())
75
-
76
- if vnet and vnet.initial_block > 0:
77
- self._initial_block = vnet.initial_block
78
- logger.info(
79
- f"Tenderly detected! Limit tracking relative to genesis block: {self._initial_block}"
80
- )
81
- else:
82
- logger.warning(
83
- f"Tenderly detected but no initial_block in config. using session start: {self._initial_block}"
84
- )
85
-
86
- logger.warning(
87
- "Monitoring Tenderly vNet block usage (Limit ~50 blocks from vNet start)"
88
- )
89
- except Exception as ex:
90
- logger.warning(f"Failed to load Tenderly config for block tracking: {ex}")
91
- except Exception as e:
92
- logger.warning(f"Failed to init block tracking: {e}")
68
+ from iwa.core.constants import get_tenderly_config_path
69
+ from iwa.core.models import TenderlyConfig
70
+
71
+ profile = Config().core.tenderly_profile
72
+ config_path = get_tenderly_config_path(profile)
73
+
74
+ if not config_path.exists():
75
+ logger.debug(f"Tenderly config not found at {config_path}, skipping block tracking")
76
+ return
77
+
78
+ t_config = TenderlyConfig.load(config_path)
79
+ vnet = t_config.vnets.get(self.chain.name)
80
+ if not vnet:
81
+ vnet = t_config.vnets.get(self.chain.name.lower())
82
+
83
+ if vnet and vnet.initial_block > 0:
84
+ self._initial_block = vnet.initial_block
85
+ logger.info(f"Tenderly block tracking enabled (genesis: {self._initial_block})")
86
+ else:
87
+ logger.debug(f"Tenderly config exists but no initial_block for {self.chain.name}")
88
+
89
+ except Exception as ex:
90
+ logger.warning(f"Failed to load Tenderly config for block tracking: {ex}")
93
91
 
94
92
  def check_block_limit(self, show_progress_bar: bool = False):
95
93
  """Check if approaching block limit (heuristic).
@@ -160,7 +158,13 @@ class ChainInterface:
160
158
  """Initialize Web3 with current RPC."""
161
159
  rpc_url = self.chain.rpcs[self._current_rpc_index] if self.chain.rpcs else ""
162
160
  raw_web3 = Web3(Web3.HTTPProvider(rpc_url, request_kwargs={"timeout": DEFAULT_RPC_TIMEOUT}))
163
- self.web3 = RateLimitedWeb3(raw_web3, self._rate_limiter, self)
161
+
162
+ # Use duck typing to check if current web3 is a RateLimitedWeb3 wrapper
163
+ # (isinstance check fails when RateLimitedWeb3 is mocked in tests)
164
+ if hasattr(self, "web3") and hasattr(self.web3, "set_backend"):
165
+ self.web3.set_backend(raw_web3)
166
+ else:
167
+ self.web3 = RateLimitedWeb3(raw_web3, self._rate_limiter, self)
164
168
 
165
169
  def _is_rate_limit_error(self, error: Exception) -> bool:
166
170
  """Check if error is a rate limit (429) error."""
@@ -268,30 +272,16 @@ class ChainInterface:
268
272
  if not self.chain.rpcs or len(self.chain.rpcs) <= 1:
269
273
  return False
270
274
 
271
- original_index = self._current_rpc_index
272
- attempts = 0
273
-
274
- while attempts < len(self.chain.rpcs) - 1:
275
- self._current_rpc_index = (self._current_rpc_index + 1) % len(self.chain.rpcs)
276
- attempts += 1
277
-
278
- if self._rpc_failure_counts.get(self._current_rpc_index, 0) >= 5:
279
- continue
280
-
281
- logger.info(f"Rotating RPC for {self.chain.name} to index {self._current_rpc_index}")
282
- self._init_web3()
283
-
284
- if self.check_rpc_health():
285
- return True
286
- else:
287
- logger.warning(f"RPC at index {self._current_rpc_index} failed health check")
288
- self._rpc_failure_counts[self._current_rpc_index] = (
289
- self._rpc_failure_counts.get(self._current_rpc_index, 0) + 1
290
- )
291
-
292
- self._current_rpc_index = original_index
275
+ # Simple Round Robin rotation
276
+ # We don't check health here because the health check itself might consume rate limits
277
+ # or fail flakily. Better to just switch and try the operation.
278
+ self._current_rpc_index = (self._current_rpc_index + 1) % len(self.chain.rpcs)
293
279
  self._init_web3()
294
- return False
280
+
281
+ logger.info(
282
+ f"Rotated RPC for {self.chain.name} to index {self._current_rpc_index}: {self.chain.rpcs[self._current_rpc_index]}"
283
+ )
284
+ return True
295
285
 
296
286
  def check_rpc_health(self) -> bool:
297
287
  """Check if the current RPC is healthy."""
@@ -5,7 +5,7 @@ from typing import Dict, List, Optional
5
5
  from pydantic import BaseModel
6
6
 
7
7
  from iwa.core.models import EthereumAddress
8
- from iwa.core.settings import settings
8
+ from iwa.core.secrets import secrets
9
9
  from iwa.core.utils import singleton
10
10
 
11
11
 
@@ -75,8 +75,8 @@ class Gnosis(SupportedChain):
75
75
  def __init__(self, **data):
76
76
  """Initialize with RPCs from settings (after testing override is applied)."""
77
77
  super().__init__(**data)
78
- if not self.rpcs and settings.gnosis_rpc:
79
- self.rpcs = settings.gnosis_rpc.get_secret_value().split(",")
78
+ if not self.rpcs and secrets.gnosis_rpc:
79
+ self.rpcs = secrets.gnosis_rpc.get_secret_value().split(",")
80
80
 
81
81
 
82
82
  @singleton
@@ -95,8 +95,8 @@ class Ethereum(SupportedChain):
95
95
  def __init__(self, **data):
96
96
  """Initialize with RPCs from settings (after testing override is applied)."""
97
97
  super().__init__(**data)
98
- if not self.rpcs and settings.ethereum_rpc:
99
- self.rpcs = settings.ethereum_rpc.get_secret_value().split(",")
98
+ if not self.rpcs and secrets.ethereum_rpc:
99
+ self.rpcs = secrets.ethereum_rpc.get_secret_value().split(",")
100
100
 
101
101
 
102
102
  @singleton
@@ -115,8 +115,8 @@ class Base(SupportedChain):
115
115
  def __init__(self, **data):
116
116
  """Initialize with RPCs from settings (after testing override is applied)."""
117
117
  super().__init__(**data)
118
- if not self.rpcs and settings.base_rpc:
119
- self.rpcs = settings.base_rpc.get_secret_value().split(",")
118
+ if not self.rpcs and secrets.base_rpc:
119
+ self.rpcs = secrets.base_rpc.get_secret_value().split(",")
120
120
 
121
121
 
122
122
  @singleton
@@ -152,17 +152,19 @@ class RateLimitedEth:
152
152
  delattr(self._eth, name)
153
153
 
154
154
  def _wrap_with_rate_limit(self, method, method_name):
155
- """Wrap a method with rate limiting and error handling."""
155
+ """Wrap a method with rate limiting.
156
+
157
+ Note: Error handling (rotation, retry) is NOT done here.
158
+ It is the responsibility of `ChainInterface.with_retry()` to handle
159
+ errors and rotate RPCs as needed. This wrapper only ensures
160
+ rate limiting.
161
+ """
156
162
 
157
163
  def wrapper(*args, **kwargs):
158
164
  if not self._rate_limiter.acquire(timeout=30.0):
159
165
  raise TimeoutError(f"Rate limit timeout waiting for {method_name}")
160
166
 
161
- try:
162
- return method(*args, **kwargs)
163
- except Exception as e:
164
- self._chain_interface._handle_rpc_error(e)
165
- raise
167
+ return method(*args, **kwargs)
166
168
 
167
169
  return wrapper
168
170
 
@@ -178,14 +180,23 @@ class RateLimitedWeb3:
178
180
  self._rate_limiter = rate_limiter
179
181
  self._chain_interface = chain_interface
180
182
  self._eth_wrapper = None
183
+ # Initialize eth wrapper immediately
184
+ self._update_eth_wrapper()
185
+
186
+ def set_backend(self, new_web3):
187
+ """Update the underlying Web3 instance (hot-swap)."""
188
+ self._web3 = new_web3
189
+ self._update_eth_wrapper()
190
+
191
+ def _update_eth_wrapper(self):
192
+ """Update the eth wrapper to point to the current _web3.eth."""
193
+ self._eth_wrapper = RateLimitedEth(
194
+ self._web3.eth, self._rate_limiter, self._chain_interface
195
+ )
181
196
 
182
197
  @property
183
198
  def eth(self):
184
199
  """Return rate-limited eth interface."""
185
- if self._eth_wrapper is None:
186
- self._eth_wrapper = RateLimitedEth(
187
- self._web3.eth, self._rate_limiter, self._chain_interface
188
- )
189
200
  return self._eth_wrapper
190
201
 
191
202
  def __getattr__(self, name):
@@ -67,6 +67,31 @@ def account_list(
67
67
  )
68
68
 
69
69
 
70
+ @wallet_cli.command("mnemonic")
71
+ def show_mnemonic():
72
+ """Show the master account mnemonic (requires password)"""
73
+ key_storage = KeyStorage()
74
+ try:
75
+ mnemonic = key_storage.decrypt_mnemonic()
76
+ print("\n" + "=" * 60)
77
+ print("📜 MASTER ACCOUNT MNEMONIC (BIP-39)")
78
+ print("=" * 60)
79
+ print("\nWrite down these 24 words and store them in a safe place.")
80
+ print("-" * 60)
81
+ words = mnemonic.split()
82
+ for i in range(0, 24, 4):
83
+ print(
84
+ f" {i + 1:2}. {words[i]:12} {i + 2:2}. {words[i + 1]:12} "
85
+ f"{i + 3:2}. {words[i + 2]:12} {i + 4:2}. {words[i + 3]:12}"
86
+ )
87
+ print("-" * 60)
88
+ print("\n⚠️ Keep this phrase secret! Anyone with it can access your funds.")
89
+ print("=" * 60)
90
+ except Exception as e:
91
+ typer.echo(f"Error: {e}")
92
+ raise typer.Exit(code=1) from e
93
+
94
+
70
95
  @wallet_cli.command("send")
71
96
  def account_send(
72
97
  from_address_or_tag: str = typer.Option(..., "--from", "-f", help="From address or tag"),
@@ -164,10 +189,10 @@ def web_server(
164
189
  host: str = typer.Option("127.0.0.1", "--host", "-h", help="Host to listen on"),
165
190
  ):
166
191
  """Start Web Interface."""
167
- from iwa.core.settings import settings
192
+ from iwa.core.models import Config
168
193
  from iwa.web.server import run_server
169
194
 
170
- server_port = port or settings.web_port
195
+ server_port = port or Config().core.web_port
171
196
  typer.echo(f"Starting web server on http://{host}:{server_port}")
172
197
  run_server(host=host, port=server_port)
173
198
 
@@ -6,14 +6,15 @@ from iwa.core.types import EthereumAddress
6
6
 
7
7
  PROJECT_ROOT = Path(__file__).parent.parent.parent.parent
8
8
 
9
- # Data directory for sensitive/runtime files
10
- DATA_DIR = PROJECT_ROOT / "data"
9
+ # Data directory for runtime files
10
+ DATA_DIR = Path("data")
11
11
 
12
- SECRETS_PATH = DATA_DIR / "secrets.env"
12
+ # secrets.env is at project root (NOT in data/)
13
+ SECRETS_PATH = Path("secrets.env")
13
14
  CONFIG_PATH = DATA_DIR / "config.yaml"
14
15
  WALLET_PATH = DATA_DIR / "wallet.json"
15
16
  BACKUP_DIR = DATA_DIR / "backup"
16
- TENDERLY_CONFIG_PATH = PROJECT_ROOT / "tenderly.yaml"
17
+ TENDERLY_CONFIG_PATH = Path("tenderly.yaml")
17
18
 
18
19
  ABI_PATH = PROJECT_ROOT / "src" / "iwa" / "core" / "contracts" / "abis"
19
20
 
@@ -25,4 +26,4 @@ DEFAULT_MECH_CONTRACT_ADDRESS = EthereumAddress("0x77af31De935740567Cf4FF1986D04
25
26
 
26
27
  def get_tenderly_config_path(profile: int = 1) -> Path:
27
28
  """Get the path to a profile-specific Tenderly config file."""
28
- return PROJECT_ROOT / f"tenderly_{profile}.yaml"
29
+ return Path(f"tenderly_{profile}.yaml")