iwa 0.0.17__tar.gz → 0.0.18__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.17/src/iwa.egg-info → iwa-0.0.18}/PKG-INFO +1 -1
  2. {iwa-0.0.17 → iwa-0.0.18}/pyproject.toml +2 -2
  3. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/chain/interface.py +1 -65
  4. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/pricing.py +1 -4
  5. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/transaction.py +72 -70
  6. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/transfer/erc20.py +8 -0
  7. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/transfer/native.py +47 -13
  8. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/activity_checker.py +2 -51
  9. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/service_manager/mech.py +43 -25
  10. {iwa-0.0.17 → iwa-0.0.18/src/iwa.egg-info}/PKG-INFO +1 -1
  11. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_chain.py +2 -97
  12. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_legacy_wallet.py +6 -6
  13. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_service_transaction.py +23 -8
  14. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_staking_router.py +14 -6
  15. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_transaction_service.py +20 -6
  16. {iwa-0.0.17 → iwa-0.0.18}/LICENSE +0 -0
  17. {iwa-0.0.17 → iwa-0.0.18}/README.md +0 -0
  18. {iwa-0.0.17 → iwa-0.0.18}/setup.cfg +0 -0
  19. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/__init__.py +0 -0
  20. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/__main__.py +0 -0
  21. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/__init__.py +0 -0
  22. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/chain/__init__.py +0 -0
  23. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/chain/errors.py +0 -0
  24. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/chain/manager.py +0 -0
  25. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/chain/models.py +0 -0
  26. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/chain/rate_limiter.py +0 -0
  27. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/cli.py +0 -0
  28. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/constants.py +0 -0
  29. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/contracts/__init__.py +0 -0
  30. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/contracts/abis/erc20.json +0 -0
  31. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/contracts/abis/multisend.json +0 -0
  32. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/contracts/abis/multisend_call_only.json +0 -0
  33. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/contracts/contract.py +0 -0
  34. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/contracts/erc20.py +0 -0
  35. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/contracts/multisend.py +0 -0
  36. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/db.py +0 -0
  37. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/ipfs.py +0 -0
  38. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/keys.py +0 -0
  39. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/mnemonic.py +0 -0
  40. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/models.py +0 -0
  41. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/monitor.py +0 -0
  42. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/plugins.py +0 -0
  43. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/secrets.py +0 -0
  44. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/__init__.py +0 -0
  45. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/account.py +0 -0
  46. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/balance.py +0 -0
  47. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/plugin.py +0 -0
  48. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/safe.py +0 -0
  49. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/transfer/__init__.py +0 -0
  50. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/transfer/base.py +0 -0
  51. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/transfer/multisend.py +0 -0
  52. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/services/transfer/swap.py +0 -0
  53. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/tables.py +0 -0
  54. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/test.py +0 -0
  55. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/tests/test_wallet.py +0 -0
  56. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/types.py +0 -0
  57. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/ui.py +0 -0
  58. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/utils.py +0 -0
  59. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/core/wallet.py +0 -0
  60. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/__init__.py +0 -0
  61. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/__init__.py +0 -0
  62. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/cow/__init__.py +0 -0
  63. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/cow/quotes.py +0 -0
  64. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/cow/swap.py +0 -0
  65. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/cow/types.py +0 -0
  66. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/cow_utils.py +0 -0
  67. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/plugin.py +0 -0
  68. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/safe.py +0 -0
  69. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/tests/test_cow.py +0 -0
  70. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/gnosis/tests/test_safe.py +0 -0
  71. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/__init__.py +0 -0
  72. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/constants.py +0 -0
  73. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/activity_checker.json +0 -0
  74. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/mech.json +0 -0
  75. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/mech_marketplace.json +0 -0
  76. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/mech_new.json +0 -0
  77. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/service_manager.json +0 -0
  78. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/service_registry.json +0 -0
  79. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/service_registry_token_utility.json +0 -0
  80. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/staking.json +0 -0
  81. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/abis/staking_token.json +0 -0
  82. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/base.py +0 -0
  83. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/mech.py +0 -0
  84. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/mech_marketplace.py +0 -0
  85. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/service.py +0 -0
  86. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/contracts/staking.py +0 -0
  87. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/importer.py +0 -0
  88. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/mech_reference.py +0 -0
  89. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/models.py +0 -0
  90. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/plugin.py +0 -0
  91. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/scripts/test_full_mech_flow.py +0 -0
  92. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/scripts/test_simple_lifecycle.py +0 -0
  93. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/service_manager/__init__.py +0 -0
  94. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/service_manager/base.py +0 -0
  95. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/service_manager/drain.py +0 -0
  96. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/service_manager/lifecycle.py +0 -0
  97. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/service_manager/staking.py +0 -0
  98. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/conftest.py +0 -0
  99. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_importer.py +0 -0
  100. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_importer_error_handling.py +0 -0
  101. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_mech_contracts.py +0 -0
  102. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_olas_contracts.py +0 -0
  103. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_olas_integration.py +0 -0
  104. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_olas_models.py +0 -0
  105. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_olas_view.py +0 -0
  106. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_olas_view_actions.py +0 -0
  107. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_olas_view_modals.py +0 -0
  108. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_plugin.py +0 -0
  109. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_plugin_full.py +0 -0
  110. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_service_lifecycle.py +0 -0
  111. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_service_manager.py +0 -0
  112. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_service_manager_errors.py +0 -0
  113. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_service_manager_flows.py +0 -0
  114. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_service_manager_mech.py +0 -0
  115. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_service_manager_rewards.py +0 -0
  116. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_service_manager_validation.py +0 -0
  117. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_service_staking.py +0 -0
  118. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_staking_integration.py +0 -0
  119. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tests/test_staking_validation.py +0 -0
  120. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tui/__init__.py +0 -0
  121. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/plugins/olas/tui/olas_view.py +0 -0
  122. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tools/__init__.py +0 -0
  123. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tools/check_profile.py +0 -0
  124. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tools/list_contracts.py +0 -0
  125. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tools/release.py +0 -0
  126. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tools/reset_env.py +0 -0
  127. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tools/reset_tenderly.py +0 -0
  128. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tools/restore_backup.py +0 -0
  129. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tools/wallet_check.py +0 -0
  130. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/__init__.py +0 -0
  131. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/app.py +0 -0
  132. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/modals/__init__.py +0 -0
  133. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/modals/base.py +0 -0
  134. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/rpc.py +0 -0
  135. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/screens/__init__.py +0 -0
  136. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/screens/wallets.py +0 -0
  137. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/tests/test_app.py +0 -0
  138. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/tests/test_rpc.py +0 -0
  139. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/tests/test_wallets_refactor.py +0 -0
  140. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/tests/test_widgets.py +0 -0
  141. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/widgets/__init__.py +0 -0
  142. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/widgets/base.py +0 -0
  143. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/tui/workers.py +0 -0
  144. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/dependencies.py +0 -0
  145. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/models.py +0 -0
  146. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/accounts.py +0 -0
  147. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/olas/__init__.py +0 -0
  148. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/olas/admin.py +0 -0
  149. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/olas/funding.py +0 -0
  150. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/olas/general.py +0 -0
  151. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/olas/services.py +0 -0
  152. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/olas/staking.py +0 -0
  153. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/state.py +0 -0
  154. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/swap.py +0 -0
  155. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/routers/transactions.py +0 -0
  156. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/server.py +0 -0
  157. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/static/app.js +0 -0
  158. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/static/index.html +0 -0
  159. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/static/style.css +0 -0
  160. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/tests/test_web_endpoints.py +0 -0
  161. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/tests/test_web_olas.py +0 -0
  162. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/tests/test_web_swap.py +0 -0
  163. {iwa-0.0.17 → iwa-0.0.18}/src/iwa/web/tests/test_web_swap_coverage.py +0 -0
  164. {iwa-0.0.17 → iwa-0.0.18}/src/iwa.egg-info/SOURCES.txt +0 -0
  165. {iwa-0.0.17 → iwa-0.0.18}/src/iwa.egg-info/dependency_links.txt +0 -0
  166. {iwa-0.0.17 → iwa-0.0.18}/src/iwa.egg-info/entry_points.txt +0 -0
  167. {iwa-0.0.17 → iwa-0.0.18}/src/iwa.egg-info/requires.txt +0 -0
  168. {iwa-0.0.17 → iwa-0.0.18}/src/iwa.egg-info/top_level.txt +0 -0
  169. {iwa-0.0.17 → iwa-0.0.18}/src/tests/legacy_cow.py +0 -0
  170. {iwa-0.0.17 → iwa-0.0.18}/src/tests/legacy_safe.py +0 -0
  171. {iwa-0.0.17 → iwa-0.0.18}/src/tests/legacy_transaction_retry_logic.py +0 -0
  172. {iwa-0.0.17 → iwa-0.0.18}/src/tests/legacy_tui.py +0 -0
  173. {iwa-0.0.17 → iwa-0.0.18}/src/tests/legacy_wallets_screen.py +0 -0
  174. {iwa-0.0.17 → iwa-0.0.18}/src/tests/legacy_web.py +0 -0
  175. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_account_service.py +0 -0
  176. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_balance_service.py +0 -0
  177. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_chain_interface.py +0 -0
  178. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_chain_interface_coverage.py +0 -0
  179. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_cli.py +0 -0
  180. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_contract.py +0 -0
  181. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_db.py +0 -0
  182. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_drain_coverage.py +0 -0
  183. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_erc20.py +0 -0
  184. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_gnosis_plugin.py +0 -0
  185. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_keys.py +0 -0
  186. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_main.py +0 -0
  187. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_migration.py +0 -0
  188. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_mnemonic.py +0 -0
  189. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_modals.py +0 -0
  190. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_models.py +0 -0
  191. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_monitor.py +0 -0
  192. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_multisend.py +0 -0
  193. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_plugin_service.py +0 -0
  194. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_pricing.py +0 -0
  195. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_rate_limiter.py +0 -0
  196. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_reset_tenderly.py +0 -0
  197. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_rpc_rotation.py +0 -0
  198. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_rpc_view.py +0 -0
  199. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_safe_coverage.py +0 -0
  200. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_safe_service.py +0 -0
  201. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_service_manager_integration.py +0 -0
  202. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_service_manager_structure.py +0 -0
  203. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_staking_simple.py +0 -0
  204. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_tables.py +0 -0
  205. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_transfer_multisend.py +0 -0
  206. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_transfer_native.py +0 -0
  207. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_transfer_security.py +0 -0
  208. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_transfer_structure.py +0 -0
  209. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_transfer_swap_unit.py +0 -0
  210. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_ui_coverage.py +0 -0
  211. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_utils.py +0 -0
  212. {iwa-0.0.17 → iwa-0.0.18}/src/tests/test_workers.py +0 -0
  213. {iwa-0.0.17 → iwa-0.0.18}/src/tools/create_and_stake_service.py +0 -0
  214. {iwa-0.0.17 → iwa-0.0.18}/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.17
3
+ Version: 0.0.18
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.17"
3
+ version = "0.0.18"
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.17"
74
+ target-version = "0.0.18"
75
75
  fix = true
76
76
 
77
77
  [tool.ruff.lint]
@@ -2,9 +2,8 @@
2
2
 
3
3
  import threading
4
4
  import time
5
- from typing import Callable, Dict, Optional, Tuple, TypeVar, Union
5
+ from typing import Callable, Dict, Optional, TypeVar, Union
6
6
 
7
- from eth_account.datastructures import SignedTransaction
8
7
  from web3 import Web3
9
8
 
10
9
  from iwa.core.chain.errors import TenderlyQuotaExceededError, sanitize_rpc_url
@@ -449,69 +448,6 @@ class ChainInterface:
449
448
 
450
449
  return False
451
450
 
452
- def send_native_transfer(
453
- self,
454
- from_address: EthereumAddress,
455
- to_address: EthereumAddress,
456
- value_wei: int,
457
- sign_callback: Callable[[dict], SignedTransaction],
458
- ) -> Tuple[bool, Optional[str]]:
459
- """Send native currency transaction with retry logic."""
460
-
461
- def _do_transfer() -> Tuple[bool, Optional[str]]:
462
- tx = {
463
- "from": from_address,
464
- "to": to_address,
465
- "value": value_wei,
466
- "nonce": self.web3.eth.get_transaction_count(from_address),
467
- "chainId": self.chain.chain_id,
468
- }
469
-
470
- balance_wei = self.get_native_balance_wei(from_address)
471
- gas_price = self.web3.eth.gas_price
472
- gas_estimate = self.web3.eth.estimate_gas(tx)
473
- required_wei = value_wei + (gas_estimate * gas_price)
474
-
475
- if balance_wei < required_wei:
476
- logger.error(
477
- f"Insufficient balance. "
478
- f"Balance: {self.web3.from_wei(balance_wei, 'ether'):.4f} "
479
- f"{self.chain.native_currency}, "
480
- f"Required: {self.web3.from_wei(required_wei, 'ether'):.4f} "
481
- f"{self.chain.native_currency}"
482
- )
483
- return False, None
484
-
485
- tx["gas"] = gas_estimate
486
- tx["gasPrice"] = gas_price
487
-
488
- signed_tx = sign_callback(tx)
489
- txn_hash = self.web3.eth.send_raw_transaction(signed_tx.raw_transaction)
490
- receipt = self.web3.eth.wait_for_transaction_receipt(txn_hash)
491
-
492
- status = getattr(receipt, "status", None)
493
- if status is None and isinstance(receipt, dict):
494
- status = receipt.get("status")
495
-
496
- if receipt and status == 1:
497
- self.wait_for_no_pending_tx(from_address)
498
- logger.info(f"Transaction sent successfully. Tx Hash: {txn_hash.hex()}")
499
- # Check Tenderly block limit after each successful transaction
500
- self.check_block_limit()
501
- return True, receipt["transactionHash"].hex()
502
-
503
- logger.error("Transaction failed (status != 1)")
504
- return False, None
505
-
506
- try:
507
- return self.with_retry(
508
- _do_transfer,
509
- operation_name=f"native_transfer to {str(to_address)[:10]}...",
510
- )
511
- except Exception as e:
512
- logger.exception(f"Native transfer failed: {e}")
513
- return False, None
514
-
515
451
  def get_token_address(self, token_name: str) -> Optional[EthereumAddress]:
516
452
  """Get token address by name"""
517
453
  return self.chain.get_token_address(token_name)
@@ -19,7 +19,6 @@ class PriceService:
19
19
  """Service to fetch token prices from CoinGecko."""
20
20
 
21
21
  BASE_URL = "https://api.coingecko.com/api/v3"
22
- DEMO_URL = "https://demo-api.coingecko.com/api/v3"
23
22
 
24
23
  def __init__(self):
25
24
  """Initialize PriceService."""
@@ -60,9 +59,7 @@ class PriceService:
60
59
  max_retries = 2
61
60
  for attempt in range(max_retries + 1):
62
61
  try:
63
- # Use demo URL if API key is present, otherwise standard URL
64
- # NOTE: Demo URL is significantly more reliable for demo keys
65
- base_url = self.DEMO_URL if self.api_key else self.BASE_URL
62
+ base_url = self.BASE_URL
66
63
  url = f"{base_url}/simple/price"
67
64
  params = {"ids": token_id, "vs_currencies": vs_currency}
68
65
  headers = {}
@@ -1,6 +1,5 @@
1
1
  """Transaction service module."""
2
2
 
3
- import time
4
3
  from typing import TYPE_CHECKING, Dict, List, Optional, Tuple
5
4
 
6
5
  from loguru import logger
@@ -31,32 +30,37 @@ class TransferLogger:
31
30
  self.account_service = account_service
32
31
  self.chain_interface = chain_interface
33
32
 
34
- def log_transfers(self, receipt: Dict, tx: Dict) -> None:
33
+ def log_transfers(self, receipt: Dict) -> None:
35
34
  """Log all transfers (ERC20 and native) from a transaction receipt.
36
35
 
37
36
  Args:
38
37
  receipt: Transaction receipt containing logs.
39
- tx: Original transaction dict.
40
38
 
41
39
  """
42
- # Log native value transfer if present
43
- native_value = tx.get("value", 0)
44
- if native_value and int(native_value) > 0:
45
- self._log_native_transfer(tx, native_value)
40
+ # Get the original transaction to check for native value transfer
41
+ tx_hash = receipt.get("transactionHash") or getattr(receipt, "transactionHash", None)
42
+ if tx_hash:
43
+ try:
44
+ tx = self.chain_interface.web3.eth.get_transaction(tx_hash)
45
+ native_value = getattr(tx, "value", 0) or tx.get("value", 0) if isinstance(tx, dict) else getattr(tx, "value", 0)
46
+ if native_value and int(native_value) > 0:
47
+ from_addr = getattr(tx, "from", "") if hasattr(tx, "from") else tx.get("from", "")
48
+ # Handle AttributeDict's special 'from' attribute
49
+ if not from_addr and hasattr(tx, "__getitem__"):
50
+ from_addr = tx["from"]
51
+ to_addr = getattr(tx, "to", "") or (tx.get("to", "") if isinstance(tx, dict) else "")
52
+ self._log_native_transfer(from_addr, to_addr, native_value)
53
+ except Exception as e:
54
+ logger.debug(f"Could not get tx for native transfer logging: {e}")
46
55
 
47
56
  # Log ERC20 transfers from event logs
48
- logs = receipt.get("logs", [])
49
- if hasattr(receipt, "logs"):
50
- logs = receipt.logs
57
+ logs = receipt.get("logs", []) if isinstance(receipt, dict) else getattr(receipt, "logs", [])
51
58
 
52
59
  for log in logs:
53
60
  self._process_log(log)
54
61
 
55
- def _log_native_transfer(self, tx: Dict, value_wei: int) -> None:
62
+ def _log_native_transfer(self, from_addr: str, to_addr: str, value_wei: int) -> None:
56
63
  """Log a native currency transfer."""
57
- from_addr = tx.get("from", "")
58
- to_addr = tx.get("to", "")
59
-
60
64
  from_label = self._resolve_address_label(from_addr)
61
65
  to_label = self._resolve_address_label(to_addr)
62
66
 
@@ -213,53 +217,67 @@ class TransactionService:
213
217
  chain_name: str = "gnosis",
214
218
  tags: Optional[List[str]] = None,
215
219
  ) -> Tuple[bool, Dict]:
216
- """Sign and send a transaction with retry logic for gas."""
220
+ """Sign and send a transaction using unified retry mechanism.
221
+
222
+ Uses ChainInterface.with_retry() for consistent RPC rotation and retry logic.
223
+ Gas errors are handled by increasing gas and retrying within the same mechanism.
224
+ """
217
225
  chain_interface = ChainInterfaces().get(chain_name)
218
226
  tx = dict(transaction)
219
- max_retries = 10
220
227
 
221
228
  if not self._prepare_transaction(tx, signer_address_or_tag, chain_interface):
222
229
  return False, {}
223
230
 
224
- for attempt in range(1, max_retries + 1):
231
+ # Mutable state for retry attempts
232
+ state = {"gas_retries": 0, "max_gas_retries": 5}
233
+
234
+ def _do_sign_send_wait() -> Tuple[bool, Dict, bytes]:
235
+ """Inner operation wrapped by with_retry."""
225
236
  try:
226
237
  signed_txn = self.key_storage.sign_transaction(tx, signer_address_or_tag)
227
- txn_hash = chain_interface.web3.eth.send_raw_transaction(signed_txn.raw_transaction)
228
-
229
- # Use chain_interface.with_retry for waiting for receipt to handle timeouts/RPC errors
230
- def wait_for_receipt(tx_h=txn_hash):
231
- return chain_interface.web3.eth.wait_for_transaction_receipt(tx_h)
232
-
233
- receipt = chain_interface.with_retry(
234
- wait_for_receipt, operation_name="wait_for_receipt"
238
+ txn_hash = chain_interface.web3.eth.send_raw_transaction(
239
+ signed_txn.raw_transaction
235
240
  )
241
+ receipt = chain_interface.web3.eth.wait_for_transaction_receipt(txn_hash)
236
242
 
237
- if receipt and getattr(receipt, "status", None) == 1:
238
- signer_account = self.account_service.resolve_account(signer_address_or_tag)
239
- chain_interface.wait_for_no_pending_tx(signer_account.address)
240
- logger.info(f"Transaction sent successfully. Tx Hash: {txn_hash.hex()}")
241
-
242
- self._log_successful_transaction(
243
- receipt, tx, signer_account, chain_name, txn_hash, tags, chain_interface
244
- )
245
- return True, receipt
243
+ status = getattr(receipt, "status", None)
244
+ if status is None and isinstance(receipt, dict):
245
+ status = receipt.get("status")
246
246
 
247
- # Transaction reverted
247
+ if receipt and status == 1:
248
+ return True, receipt, txn_hash
249
+ # Transaction mined but reverted - don't retry
248
250
  logger.error("Transaction failed (status 0).")
249
- return False, {}
251
+ raise ValueError("Transaction reverted")
250
252
 
251
253
  except web3_exceptions.Web3RPCError as e:
252
- if self._handle_gas_error(e, tx, attempt, max_retries):
253
- continue
254
- return False, {}
254
+ # Handle gas errors by increasing gas and re-raising
255
+ self._handle_gas_retry(e, tx, state)
256
+ raise # Re-raise to trigger with_retry's retry mechanism
255
257
 
256
- except Exception as e:
257
- # Attempt RPC rotation
258
- if self._handle_generic_error(e, chain_interface, attempt, max_retries):
259
- continue
258
+ try:
259
+ success, receipt, txn_hash = chain_interface.with_retry(
260
+ _do_sign_send_wait,
261
+ operation_name=f"sign_and_send to {tx.get('to', 'unknown')[:10]}...",
262
+ )
263
+ if success:
264
+ signer_account = self.account_service.resolve_account(signer_address_or_tag)
265
+ chain_interface.wait_for_no_pending_tx(signer_account.address)
266
+ logger.info(f"Transaction sent successfully. Tx Hash: {txn_hash.hex()}")
267
+ self._log_successful_transaction(
268
+ receipt, tx, signer_account, chain_name, txn_hash, tags, chain_interface
269
+ )
270
+ return True, receipt
271
+ return False, {}
272
+ except ValueError as e:
273
+ # Transaction reverted - already logged
274
+ if "reverted" in str(e).lower():
260
275
  return False, {}
261
-
262
- return False, {}
276
+ logger.exception(f"Transaction failed: {e}")
277
+ return False, {}
278
+ except Exception as e:
279
+ logger.exception(f"Transaction failed after retries: {e}")
280
+ return False, {}
263
281
 
264
282
  def _prepare_transaction(self, tx: dict, signer_tag: str, chain_interface) -> bool:
265
283
  """Ensure nonce and chainId are set."""
@@ -274,32 +292,16 @@ class TransactionService:
274
292
  tx["chainId"] = chain_interface.chain.chain_id
275
293
  return True
276
294
 
277
- def _handle_gas_error(self, e, tx, attempt, max_retries) -> bool:
278
- err_text = str(e)
279
- if self._is_gas_too_low_error(err_text) and attempt < max_retries:
280
- logger.warning(
281
- f"Gas too low error detected. Retrying with increased gas (Attempt {attempt}/{max_retries})..."
282
- )
295
+ def _handle_gas_retry(self, e: Exception, tx: dict, state: dict) -> None:
296
+ """Increase gas if error is gas-related and retries remaining."""
297
+ if self._is_gas_too_low_error(str(e)) and state["gas_retries"] < state["max_gas_retries"]:
283
298
  current_gas = int(tx.get("gas", 30_000))
284
299
  tx["gas"] = int(current_gas * 1.5)
285
- tx["gas"] = int(current_gas * 1.5)
286
- # Exponential backoff for gas errors
287
- time.sleep(min(2**attempt, 30))
288
- return True
289
- logger.exception(f"Error sending transaction: {e}")
290
- return False
291
-
292
- def _handle_generic_error(self, e, chain_interface, attempt, max_retries) -> bool:
293
- if attempt < max_retries:
294
- logger.warning(f"Error encountered: {e}. Attempting to rotate RPC...")
295
-
296
- if chain_interface.rotate_rpc():
297
- logger.info("Retrying with new RPC...")
298
- # Exponential backoff
299
- time.sleep(min(2**attempt, 30))
300
- return True
301
- logger.exception(f"Unexpected error sending transaction: {e}")
302
- return False
300
+ state["gas_retries"] += 1
301
+ logger.warning(
302
+ f"Gas too low, increasing to {tx['gas']} "
303
+ f"(attempt {state['gas_retries']}/{state['max_gas_retries']})"
304
+ )
303
305
 
304
306
  def _log_successful_transaction(
305
307
  self, receipt, tx, signer_account, chain_name, txn_hash, tags, chain_interface
@@ -323,7 +325,7 @@ class TransactionService:
323
325
 
324
326
  # Log transfer events (ERC20 and native value)
325
327
  transfer_logger = TransferLogger(self.account_service, chain_interface)
326
- transfer_logger.log_transfers(receipt, tx)
328
+ transfer_logger.log_transfers(receipt)
327
329
 
328
330
  except Exception as log_err:
329
331
  logger.warning(f"Failed to log transaction: {log_err}")
@@ -64,6 +64,14 @@ class ERC20TransferMixin:
64
64
  value_eur=v_eur,
65
65
  tags=["erc20-transfer", "safe-transaction"],
66
66
  )
67
+
68
+ # Log transfers extracted from receipt events
69
+ if receipt:
70
+ from iwa.core.services.transaction import TransferLogger
71
+
72
+ transfer_logger = TransferLogger(self.account_service, interface)
73
+ transfer_logger.log_transfers(receipt)
74
+
67
75
  return tx_hash
68
76
 
69
77
  def _send_erc20_via_eoa(
@@ -61,6 +61,15 @@ class NativeTransferMixin:
61
61
  value_eur=v_eur,
62
62
  tags=["native-transfer", "safe-transaction"],
63
63
  )
64
+
65
+ # Log transfers extracted from receipt events
66
+ if receipt:
67
+ from iwa.core.services.transaction import TransferLogger
68
+
69
+ interface = ChainInterfaces().get(chain_name)
70
+ transfer_logger = TransferLogger(self.account_service, interface)
71
+ transfer_logger.log_transfers(receipt)
72
+
64
73
  return tx_hash
65
74
 
66
75
  def _send_native_via_eoa(
@@ -74,20 +83,38 @@ class NativeTransferMixin:
74
83
  to_tag: Optional[str],
75
84
  token_symbol: str,
76
85
  ) -> Optional[str]:
77
- """Send native currency via EOA (externally owned account)."""
78
- success, tx_hash = chain_interface.send_native_transfer(
79
- from_address=from_account.address,
80
- to_address=to_address,
81
- value_wei=amount_wei,
82
- sign_callback=lambda tx: self.key_storage.sign_transaction(tx, from_account.address),
86
+ """Send native currency via EOA using unified TransactionService."""
87
+ # Build transaction dict
88
+ try:
89
+ gas_price = chain_interface.web3.eth.gas_price
90
+ gas_estimate = chain_interface.web3.eth.estimate_gas({
91
+ "from": from_account.address,
92
+ "to": to_address,
93
+ "value": amount_wei,
94
+ })
95
+ except Exception as e:
96
+ logger.error(f"Failed to estimate gas for native transfer: {e}")
97
+ return None
98
+
99
+ tx = {
100
+ "from": from_account.address,
101
+ "to": to_address,
102
+ "value": amount_wei,
103
+ "gas": gas_estimate,
104
+ "gasPrice": gas_price,
105
+ }
106
+
107
+ # Use unified TransactionService
108
+ success, receipt = self.transaction_service.sign_and_send(
109
+ tx, from_account.address, chain_name, tags=["native-transfer"]
83
110
  )
84
- if success and tx_hash:
85
- # Get receipt for gas calculation
86
- receipt = None
87
- try:
88
- receipt = chain_interface.web3.eth.get_transaction_receipt(tx_hash)
89
- except Exception as e:
90
- logger.warning(f"Could not get receipt for {tx_hash}: {e}")
111
+
112
+ if success and receipt:
113
+ tx_hash = receipt.get("transactionHash", b"")
114
+ if hasattr(tx_hash, "hex"):
115
+ tx_hash = tx_hash.hex()
116
+ elif isinstance(tx_hash, bytes):
117
+ tx_hash = tx_hash.hex()
91
118
 
92
119
  gas_cost, gas_value_eur = self._calculate_gas_info(receipt, chain_name)
93
120
  p_eur, v_eur = self._get_token_price_info(token_symbol, amount_wei, chain_name)
@@ -106,6 +133,13 @@ class NativeTransferMixin:
106
133
  value_eur=v_eur,
107
134
  tags=["native-transfer"],
108
135
  )
136
+
137
+ # Log transfers extracted from receipt events
138
+ from iwa.core.services.transaction import TransferLogger
139
+
140
+ transfer_logger = TransferLogger(self.account_service, chain_interface)
141
+ transfer_logger.log_transfers(receipt)
142
+
109
143
  return tx_hash
110
144
  return None
111
145
 
@@ -10,8 +10,6 @@ requests relative to the time elapsed since the last checkpoint.
10
10
 
11
11
  from typing import Tuple
12
12
 
13
- from web3 import Web3
14
-
15
13
  from iwa.core.constants import DEFAULT_MECH_CONTRACT_ADDRESS
16
14
  from iwa.core.types import EthereumAddress
17
15
  from iwa.plugins.olas.contracts.base import OLAS_ABI_PATH, ContractInstance
@@ -70,9 +68,6 @@ class ActivityCheckerContract(ContractInstance):
70
68
  def get_multisig_nonces(self, multisig: EthereumAddress) -> Tuple[int, int]:
71
69
  """Get the nonces for a multisig address.
72
70
 
73
- This method reads directly from the source contracts to ensure fresh data
74
- and compatibility with Legacy/MM contracts.
75
-
76
71
  Args:
77
72
  multisig: The multisig address to check.
78
73
 
@@ -82,52 +77,8 @@ class ActivityCheckerContract(ContractInstance):
82
77
  - mech_requests_count: Total mech requests made
83
78
 
84
79
  """
85
- # 1. Get Safe Nonce
86
- safe_nonce = 0
87
- try:
88
- # Minimal ABI for Safe nonce
89
- safe_abi = [{"name": "nonce", "type": "function", "inputs": [], "outputs": [{"type": "uint256"}]}]
90
- safe_contract = self.chain_interface.web3._web3.eth.contract(
91
- address=Web3.to_checksum_address(multisig), abi=safe_abi
92
- )
93
- safe_nonce = safe_contract.functions.nonce().call()
94
- except Exception as e:
95
- # Fallback or log error? If safe read fails, something is very wrong.
96
- # But we don't want to crash the whole status check if possible.
97
- # For now, let's log and keep 0 or re-raise if critical.
98
- # safe_nonce is critical for liveness check (diffNonces).
99
- from loguru import logger
100
- logger.warning(f"Failed to read Safe nonce for {multisig}: {e}")
101
-
102
- # 2. Get Mech Requests Count
103
- mech_requests = 0
104
-
105
- if self.mech_marketplace:
106
- # Case A: Marketplace (MM)
107
- try:
108
- # Minimal ABI for Marketplace mapRequestCounts
109
- mp_abi = [{"name": "mapRequestCounts", "type": "function", "inputs": [{"type": "address"}], "outputs": [{"type": "uint256"}]}]
110
- mp_contract = self.chain_interface.web3._web3.eth.contract(
111
- address=Web3.to_checksum_address(self.mech_marketplace), abi=mp_abi
112
- )
113
- mech_requests = mp_contract.functions.mapRequestCounts(multisig).call()
114
- except Exception as e:
115
- from loguru import logger
116
- logger.warning(f"Failed to read Marketplace requests for {multisig}: {e}")
117
- else:
118
- # Case B: Legacy (AgentMech)
119
- try:
120
- # Minimal ABI for AgentMech getRequestsCount
121
- mech_abi = [{"name": "getRequestsCount", "type": "function", "inputs": [{"type": "address"}], "outputs": [{"type": "uint256"}]}]
122
- mech_contract = self.chain_interface.web3._web3.eth.contract(
123
- address=Web3.to_checksum_address(self.agent_mech), abi=mech_abi
124
- )
125
- mech_requests = mech_contract.functions.getRequestsCount(multisig).call()
126
- except Exception as e:
127
- from loguru import logger
128
- logger.warning(f"Failed to read AgentMech requests for {multisig}: {e}")
129
-
130
- return (safe_nonce, mech_requests)
80
+ nonces = self.contract.functions.getMultisigNonces(multisig).call()
81
+ return (nonces[0], nonces[1])
131
82
 
132
83
  def is_ratio_pass(
133
84
  self,
@@ -140,11 +140,13 @@ class MechManagerMixin:
140
140
  )
141
141
  if use_marketplace:
142
142
  priority_mech = priority_mech or detected_priority_mech
143
+ mech_address = mech_address or detected_marketplace
143
144
 
144
145
  if use_marketplace:
145
146
  return self._send_marketplace_mech_request(
146
147
  data=data,
147
148
  value=value,
149
+ marketplace_address=mech_address,
148
150
  priority_mech=priority_mech,
149
151
  max_delivery_rate=max_delivery_rate,
150
152
  payment_type=payment_type,
@@ -260,10 +262,39 @@ class MechManagerMixin:
260
262
 
261
263
  return True
262
264
 
265
+ def _resolve_marketplace_config(
266
+ self, marketplace_addr: Optional[str], priority_addr: Optional[str]
267
+ ) -> tuple[str, str]:
268
+ """Resolve marketplace and priority mech addresses. Returns (marketplace, priority)."""
269
+ chain_name = self.chain_name if self.service else getattr(self, "chain_name", "gnosis")
270
+ protocol_contracts = OLAS_CONTRACTS.get(chain_name, {})
271
+
272
+ resolved_mp = marketplace_addr or protocol_contracts.get("OLAS_MECH_MARKETPLACE")
273
+ if not resolved_mp:
274
+ raise ValueError(f"Mech Marketplace address not found for chain {chain_name}")
275
+
276
+ if not priority_addr:
277
+ raise ValueError("priority_mech is required for marketplace requests")
278
+
279
+ return str(resolved_mp), Web3.to_checksum_address(priority_addr)
280
+
281
+ def _prepare_marketplace_params(
282
+ self,
283
+ value: Optional[int],
284
+ max_delivery_rate: Optional[int],
285
+ payment_type: Optional[bytes],
286
+ ) -> tuple[int, int, bytes]:
287
+ """Prepare default values for marketplace parameters."""
288
+ p_type = payment_type or bytes.fromhex(PAYMENT_TYPE_NATIVE)
289
+ val = value if value is not None else 10_000_000_000_000_000
290
+ rate = max_delivery_rate if max_delivery_rate is not None else val
291
+ return val, rate, p_type
292
+
263
293
  def _send_marketplace_mech_request(
264
294
  self,
265
295
  data: bytes,
266
296
  value: Optional[int] = None,
297
+ marketplace_address: Optional[str] = None,
267
298
  priority_mech: Optional[str] = None,
268
299
  max_delivery_rate: Optional[int] = None,
269
300
  payment_type: Optional[bytes] = None,
@@ -275,43 +306,30 @@ class MechManagerMixin:
275
306
  logger.error("No active service")
276
307
  return None
277
308
 
278
- multisig_address = self.service.multisig_address
279
- chain_name = self.chain_name if self.service else getattr(self, "chain_name", "gnosis")
280
- protocol_contracts = OLAS_CONTRACTS.get(chain_name, {})
281
- marketplace_address = protocol_contracts.get("OLAS_MECH_MARKETPLACE")
282
-
283
- if not marketplace_address:
284
- logger.error(f"Mech Marketplace address not found for chain {chain_name}")
285
- return None
286
-
287
- if not priority_mech:
288
- logger.error("priority_mech is required for marketplace requests")
309
+ try:
310
+ marketplace_address, priority_mech = self._resolve_marketplace_config(
311
+ marketplace_address, priority_mech
312
+ )
313
+ except ValueError as e:
314
+ logger.error(e)
289
315
  return None
290
316
 
291
- priority_mech = Web3.to_checksum_address(priority_mech)
292
- marketplace = MechMarketplaceContract(str(marketplace_address), chain_name=chain_name)
317
+ marketplace = MechMarketplaceContract(marketplace_address, chain_name=self.chain_name)
293
318
 
294
319
  if not self._validate_priority_mech(marketplace, priority_mech):
295
320
  return None
296
321
 
297
- # Set defaults for payment
298
- if payment_type is None:
299
- payment_type = bytes.fromhex(PAYMENT_TYPE_NATIVE)
300
-
301
- if value is None:
302
- value = 10_000_000_000_000_000
303
- logger.info(f"Using default value: {value} wei (0.01 xDAI)")
304
-
305
- if max_delivery_rate is None:
306
- max_delivery_rate = value
307
- logger.info(f"Using value as max_delivery_rate: {max_delivery_rate}")
322
+ # Set defaults for payment and delivery
323
+ value, max_delivery_rate, payment_type = self._prepare_marketplace_params(
324
+ value, max_delivery_rate, payment_type
325
+ )
308
326
 
309
327
  if not self._validate_marketplace_params(marketplace, response_timeout, payment_type):
310
328
  return None
311
329
 
312
330
  # Prepare transaction
313
331
  tx_data = marketplace.prepare_request_tx(
314
- from_address=multisig_address,
332
+ from_address=self.service.multisig_address,
315
333
  request_data=data,
316
334
  priority_mech=priority_mech,
317
335
  response_timeout=response_timeout,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iwa
3
- Version: 0.0.17
3
+ Version: 0.0.18
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