ipor-fusion 4.0.0.dev274__tar.gz → 4.0.0.dev282__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 (349) hide show
  1. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/AGENTS.md +8 -3
  2. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/PKG-INFO +10 -2
  3. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/README.md +9 -1
  4. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/pyproject.toml +1 -1
  5. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/skills/ipor-deploy-vault/SKILL.md +5 -3
  6. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/__init__.py +34 -0
  7. ipor_fusion-4.0.0.dev282/src/ipor_fusion/cli/address_cmd.py +108 -0
  8. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/main.py +2 -0
  9. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/errors.py +9 -0
  10. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/universal.py +38 -7
  11. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/guide/quickstart.md +5 -3
  12. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/mcp/models.py +41 -0
  13. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/mcp/server.py +55 -2
  14. ipor_fusion-4.0.0.dev282/src/ipor_fusion/registry.py +269 -0
  15. ipor_fusion-4.0.0.dev282/tests/test_cli_address.py +81 -0
  16. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_fuse_encoding.py +72 -0
  17. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_guide.py +2 -18
  18. ipor_fusion-4.0.0.dev282/tests/test_mcp_address.py +73 -0
  19. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_mcp_models.py +11 -0
  20. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_public_api.py +36 -0
  21. ipor_fusion-4.0.0.dev282/tests/test_registry.py +227 -0
  22. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.claude-plugin/marketplace.json +0 -0
  23. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.claude-plugin/plugin.json +0 -0
  24. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.env.example +0 -0
  25. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.gemini/settings.json +0 -0
  26. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.git-blame-ignore-revs +0 -0
  27. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.github/workflows/cd.yml +0 -0
  28. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.github/workflows/ci.yml +0 -0
  29. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.github/workflows/commit-lint.yml +0 -0
  30. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.github/workflows/notify-slack.yml +0 -0
  31. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.github/workflows/python-build.yml +0 -0
  32. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.github/workflows/python-publish.yml +0 -0
  33. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.github/workflows/release.yml +0 -0
  34. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.github/workflows/report-slack.yml +0 -0
  35. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.gitignore +0 -0
  36. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.mcp.json +0 -0
  37. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.pre-commit-config.yaml +0 -0
  38. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/.python-version +0 -0
  39. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/CHANGELOG.md +0 -0
  40. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/CLAUDE.md +0 -0
  41. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/CODEOWNERS +0 -0
  42. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/LICENSE +0 -0
  43. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/MIGRATION_4.md +0 -0
  44. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/build.sh +0 -0
  45. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/examples/CONTRIBUTING.md +0 -0
  46. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/examples/README.md +0 -0
  47. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  48. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  49. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  50. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  51. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/examples/external_state_margin_leg_base.py +0 -0
  52. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/examples/simple_aave_v3_supply_base.py +0 -0
  53. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/pytest.ini +0 -0
  54. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/scripts/commit-check.sh +0 -0
  55. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/scripts/crosschain_readiness.py +0 -0
  56. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/about.py +0 -0
  57. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cache.py +0 -0
  58. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/chains.py +0 -0
  59. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/__init__.py +0 -0
  60. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  61. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/config_cmd.py +0 -0
  62. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/config_store.py +0 -0
  63. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/market_cmd.py +0 -0
  64. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/options.py +0 -0
  65. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  66. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  67. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/vault_health.py +0 -0
  68. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  69. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  70. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  71. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/config/__init__.py +0 -0
  72. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/config/roles.py +0 -0
  73. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/__init__.py +0 -0
  74. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/access.py +0 -0
  75. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/address.py +0 -0
  76. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/context.py +0 -0
  77. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/context_manager.py +0 -0
  78. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/contract.py +0 -0
  79. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/erc20.py +0 -0
  80. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/external_state_executor.py +0 -0
  81. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/fee_manager.py +0 -0
  82. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/fuse.py +0 -0
  83. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/fuse_action.py +0 -0
  84. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/fusion_factory.py +0 -0
  85. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/logs.py +0 -0
  86. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/multicall.py +0 -0
  87. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/oracle.py +0 -0
  88. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/plasma_vault.py +0 -0
  89. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/rewards_manager.py +0 -0
  90. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/simulation.py +0 -0
  91. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/simulation_result.py +0 -0
  92. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  93. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/__init__.py +0 -0
  94. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  95. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  96. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  97. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  98. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  99. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  100. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  101. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  102. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  103. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/contracts.py +0 -0
  104. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/discovery.py +0 -0
  105. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/errors.py +0 -0
  106. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  107. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  108. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  109. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  110. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/lane.py +0 -0
  111. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/logs.py +0 -0
  112. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/messages.py +0 -0
  113. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/simulation.py +0 -0
  114. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  115. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  116. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  117. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  118. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  119. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/crosschain/transport.py +0 -0
  120. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/dependency_graph.py +0 -0
  121. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/entry_cli.py +0 -0
  122. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/entry_mcp.py +0 -0
  123. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/explorer.py +0 -0
  124. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/field_docs.py +0 -0
  125. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/__init__.py +0 -0
  126. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  127. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/async_action.py +0 -0
  128. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/base.py +0 -0
  129. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  130. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/erc4626.py +0 -0
  131. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  132. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/events.py +0 -0
  133. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/external_state.py +0 -0
  134. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
  135. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  136. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  137. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/hypercore.py +0 -0
  138. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
  139. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/merkl.py +0 -0
  140. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/morpho.py +0 -0
  141. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  142. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  143. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/guide/__init__.py +0 -0
  144. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/guide/architecture.md +0 -0
  145. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/guide/glossary.md +0 -0
  146. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/guide/invariants.md +0 -0
  147. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/hypercore/__init__.py +0 -0
  148. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/market_ids.py +0 -0
  149. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/market_info.py +0 -0
  150. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/mcp/__init__.py +0 -0
  151. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/mcp/guide.py +0 -0
  152. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/morpho_api.py +0 -0
  153. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/py.typed +0 -0
  154. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/__init__.py +0 -0
  155. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/aave_v3.py +0 -0
  156. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/aave_v4.py +0 -0
  157. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/compound_v3.py +0 -0
  158. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/hypercore.py +0 -0
  159. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  160. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/lending_health.py +0 -0
  161. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/morpho.py +0 -0
  162. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  163. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
  164. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  165. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/position_manager.py +0 -0
  166. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  167. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  168. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/readers/unpriceable.py +0 -0
  169. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/substrates.py +0 -0
  170. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/types.py +0 -0
  171. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/validation.py +0 -0
  172. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/vault_data.py +0 -0
  173. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/vault_erc20.py +0 -0
  174. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/vault_info.py +0 -0
  175. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/vault_managers.py +0 -0
  176. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/vault_positions.py +0 -0
  177. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/src/ipor_fusion/vault_reads.py +0 -0
  178. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/UniswapV3UniversalRouter.py +0 -0
  179. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_crosschain.py +0 -0
  180. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_crosschain_lifecycle.py +0 -0
  181. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_crosschain_recovery.py +0 -0
  182. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_euler_v2.py +0 -0
  183. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_event_args.py +0 -0
  184. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_fake_rpc.py +0 -0
  185. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_foundry.py +0 -0
  186. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_golden.py +0 -0
  187. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_guide.py +0 -0
  188. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_hypercore_model.py +0 -0
  189. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_hypercore_shadow.py +0 -0
  190. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_live.py +0 -0
  191. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_multicall.py +0 -0
  192. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_oracle_mapping_fake.py +0 -0
  193. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_simulate.py +0 -0
  194. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/_validation.py +0 -0
  195. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/addresses.py +0 -0
  196. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/conftest.py +0 -0
  197. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/constants.py +0 -0
  198. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  199. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/hypercore_market55.json +0 -0
  200. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
  201. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
  202. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
  203. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
  204. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
  205. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
  206. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
  207. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
  208. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_blue.json +0 -0
  209. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
  210. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
  211. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
  212. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
  213. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
  214. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
  215. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
  216. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/simulate_v1_request.json +0 -0
  217. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/clean.json +0 -0
  218. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
  219. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  220. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
  221. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
  222. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
  223. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
  224. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/fetched.json +0 -0
  225. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
  226. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/full.json +0 -0
  227. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
  228. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/full.txt +0 -0
  229. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/rich.json +0 -0
  230. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
  231. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  232. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_about.py +0 -0
  233. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_access_manager.py +0 -0
  234. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cache.py +0 -0
  235. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_chains.py +0 -0
  236. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_changelog.py +0 -0
  237. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_commands.py +0 -0
  238. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_config_store.py +0 -0
  239. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_helpers.py +0 -0
  240. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_hypercore.py +0 -0
  241. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_lending_health.py +0 -0
  242. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_market_golden.py +0 -0
  243. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_market_morpho_blue.py +0 -0
  244. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_mcp_parity.py +0 -0
  245. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_oracle_mapping.py +0 -0
  246. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_oracle_mapping_golden.py +0 -0
  247. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_pending_requests_scan.py +0 -0
  248. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_role_accounts.py +0 -0
  249. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_vault_info_golden.py +0 -0
  250. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_vault_predates_getters.py +0 -0
  251. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_cli_vault_validate.py +0 -0
  252. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_contract_call.py +0 -0
  253. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_contract_encoder.py +0 -0
  254. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_ccip_events.py +0 -0
  255. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_ccip_indexer.py +0 -0
  256. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_ccip_quote.py +0 -0
  257. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_chainlink.py +0 -0
  258. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_contracts.py +0 -0
  259. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_encoding.py +0 -0
  260. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_errors.py +0 -0
  261. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_lane.py +0 -0
  262. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_layering.py +0 -0
  263. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_readiness.py +0 -0
  264. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_readiness_report.py +0 -0
  265. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_crosschain_transport.py +0 -0
  266. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_docs_typing.py +0 -0
  267. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_erc20.py +0 -0
  268. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_error_hierarchy.py +0 -0
  269. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_examples_composed_hypercore.py +0 -0
  270. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_examples_crosschain.py +0 -0
  271. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  272. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_examples_vaults.py +0 -0
  273. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_explorer.py +0 -0
  274. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_external_state_events.py +0 -0
  275. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_external_state_executor.py +0 -0
  276. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_fee_manager.py +0 -0
  277. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_fusion_instance.py +0 -0
  278. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_governance_wrappers.py +0 -0
  279. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_hypercore_deployment.py +0 -0
  280. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_hypercore_events.py +0 -0
  281. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_hypercore_flow.py +0 -0
  282. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_hypercore_live.py +0 -0
  283. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_hypercore_outcome.py +0 -0
  284. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_hypercore_readers.py +0 -0
  285. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_hypercore_simulation.py +0 -0
  286. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_logs.py +0 -0
  287. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_mcp_hypercore.py +0 -0
  288. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_mcp_server.py +0 -0
  289. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_mcp_vault_validate.py +0 -0
  290. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_multicall.py +0 -0
  291. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_oracle.py +0 -0
  292. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_oracle_mapping.py +0 -0
  293. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_plasma_vault.py +0 -0
  294. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_public_type_reachability.py +0 -0
  295. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_reader_encoding.py +0 -0
  296. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_readiness_selection.py +0 -0
  297. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_revert_decoding.py +0 -0
  298. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_rewards_manager.py +0 -0
  299. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_roles.py +0 -0
  300. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_sdk_layering.py +0 -0
  301. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  302. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  303. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  304. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_crosschain_canary.py +0 -0
  305. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_crosschain_hypercore.py +0 -0
  306. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  307. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  308. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  309. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  310. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  311. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  312. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  313. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_examples_arbitrum.py +0 -0
  314. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_examples_base.py +0 -0
  315. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_examples_crosschain.py +0 -0
  316. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_external_state_executor_base.py +0 -0
  317. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  318. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  319. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  320. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_morpho_blue.py +0 -0
  321. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_pilot_v3.py +0 -0
  322. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  323. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  324. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  325. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  326. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_readers_integration.py +0 -0
  327. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_release_funds.py +0 -0
  328. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_swap_on_base.py +0 -0
  329. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  330. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulation_errors.py +0 -0
  331. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_simulation_observation.py +0 -0
  332. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_solidity_compiler.py +0 -0
  333. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_solidity_mirrors.py +0 -0
  334. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_substrates.py +0 -0
  335. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_types_and_events.py +0 -0
  336. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_unpriceable_tokens.py +0 -0
  337. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_validation.py +0 -0
  338. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_vault_data_block.py +0 -0
  339. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_vault_dep_graph.py +0 -0
  340. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_vault_info_fetched_golden.py +0 -0
  341. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_vault_info_onchain_base.py +0 -0
  342. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  343. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_vault_reconciliation_onchain_base.py +0 -0
  344. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_vault_simulator_blocks.py +0 -0
  345. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_web3_context.py +0 -0
  346. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/test_withdraw_manager.py +0 -0
  347. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/typed_client/consumer.py +0 -0
  348. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/tests/typed_client/rejected.py +0 -0
  349. {ipor_fusion-4.0.0.dev274 → ipor_fusion-4.0.0.dev282}/uv.lock +0 -0
@@ -198,7 +198,7 @@ the lifecycle matrix follows that.
198
198
  subpackages do not list them). Their exceptions stay in `errors` and the top
199
199
  level. `ipor_fusion.guide` keeps its own namespace. The
200
200
  public modules (`about`, `cache`, `chains`, `dependency_graph`, `errors`, `explorer`,
201
- `field_docs`, `market_ids`, `market_info`, `morpho_api`, `substrates`, `types`,
201
+ `field_docs`, `market_ids`, `market_info`, `morpho_api`, `registry`, `substrates`, `types`,
202
202
  `validation`, `vault_data`, `vault_info`) stay importable for the names they
203
203
  define and the moved names README lists; `cli`, `mcp`, every other module and
204
204
  every submodule of a public subpackage (`core.contract`, `fuses.base`, ...) are
@@ -221,7 +221,7 @@ the lifecycle matrix follows that.
221
221
  | `IporFusionMarkets`, `Roles` | `market_ids.py`, `config/roles.py` mirror `IporFusionMarkets.sol`, `Roles.sol` in `ipor-fusion/contracts/libraries/`; drift-gated by `tests/test_solidity_mirrors.py` — bump its pinned ref in the same change that syncs the mirrors An id sourced from a contracts feature branch ahead of the pinned ref goes in the test's `_AHEAD_OF_UPSTREAM` allowlist and is removed when the ref catches up |
222
222
  | substrate decoders | `substrates.py` registry mirrors each market's `contracts/fuses/<protocol>/*SubstrateLib.sol` or `*FuseLib.sol` |
223
223
  | `vault_info` / `fusion market` JSON shapes | the builders and their TypedDicts (`VaultInfoJson`, `MorphoBlueMarketJson`, `MetaMorphoV1Json` / `MetaMorphoV2Json`) in `vault_info.py` / `market_info.py`, models in `mcp/models.py` (`extra="forbid"`, the published schema), the `VaultInfoJson`-typed `_full_vault_info_dict` fixture in `test_mcp_models.py` |
224
- | CLI command set | every CLI command has a matching tool in `mcp/server.py` with the same arguments (`changelog` maps to `server_info`; `--json` and display filters are CLI-only); `tests/test_cli_mcp_parity.py` enforces it, and both resolve chain and provider through `cli/config_store.resolve_chain_id` |
224
+ | CLI command set | every CLI command has a matching tool in `mcp/server.py` with the same arguments (`changelog` maps to `server_info`; `--json` and display filters are CLI-only); `tests/test_cli_mcp_parity.py` enforces it, and the RPC-backed commands resolve chain and provider through `cli/config_store.resolve_chain_id` (`fusion address` reads no RPC: an omitted chain means every registry chain) |
225
225
 
226
226
  ## Layout (`src/ipor_fusion/`)
227
227
 
@@ -258,6 +258,9 @@ the lifecycle matrix follows that.
258
258
  `ctx.cache` (`Web3Context(cache=...)`, default `default_contract_cache()` under
259
259
  `$XDG_CACHE_HOME/ipor-fusion/`) or `get_contract_name(cache=...)`. Never cache an
260
260
  absence (no code, no answer): it can change at a later block.
261
+ `registry.py` the ipor-abi address registry (`fetch_address_registry` →
262
+ `AddressRegistry`, one raw-GitHub file per chain in `REGISTRY_CHAIN_IDS`, cached ten
263
+ minutes in the process, for good at a commit ref) and the `fusion address` documents;
261
264
  `morpho_api.py` the Morpho public GraphQL API client (`fetch_market`, `fetch_vault`,
262
265
  `PUBLIC_ALLOCATOR_ADDRESSES`; it narrows the GraphQL body from `object`);
263
266
  `market_info.py` — `build_morpho_blue_market_json`, `build_meta_morpho_json`, the
@@ -481,6 +484,7 @@ byte, e.g. Ebisu ZAPPER/REGISTRY).
481
484
 
482
485
  ## CLI and MCP
483
486
 
487
+ `fusion address` (lookup, names, list; the ipor-abi registry through `registry.py`),
484
488
  `fusion config` (set-provider, set-etherscan-key, show), `fusion market`
485
489
  (morpho-blue, meta-morpho), `fusion vault` (add, remove, list, info, validate,
486
490
  role-accounts, oracle-mapping). `vault info` runs independent fetch pipelines
@@ -498,7 +502,8 @@ inject a cache.
498
502
  Every CLI command has an MCP tool (`fusion changelog` maps to `server_info`;
499
503
  the rest share names). Read-only: `vault_info`, `vault_validate`,
500
504
  `vault_list`, `vault_role_accounts`, `vault_oracle_mapping`, `market_morpho_blue`,
501
- `market_meta_morpho`, `config_show`, `server_info`. Mutating: `vault_add`,
505
+ `market_meta_morpho`, `address_lookup`, `address_names`, `address_list`,
506
+ `config_show`, `server_info`. Mutating: `vault_add`,
502
507
  `vault_remove`, `config_set_provider`, `config_set_etherscan_key`. Every new
503
508
  CLI command gets a matching MCP tool with the same argument names; an optional
504
509
  chain or block is `None` when omitted (`ChainArg`, `BlockArg`), never a `0`
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev274
3
+ Version: 4.0.0.dev282
4
4
  Summary: The IPOR Fusion SDK for Python
5
5
  Project-URL: homepage, https://ipor.io
6
6
  Project-URL: repository, https://github.com/IPOR-Labs/ipor-fusion.py
@@ -168,7 +168,8 @@ receipt = vault.execute([action]).send(ctx)
168
168
  ```
169
169
 
170
170
  Fuse, factory and manager addresses per chain are published in
171
- [ipor-abi](https://github.com/IPOR-Labs/ipor-abi) (`mainnet/mainnet-<chain>-fusion/addresses.json`).
171
+ [ipor-abi](https://github.com/IPOR-Labs/ipor-abi) (`mainnet/mainnet-<chain>-fusion/addresses.json`);
172
+ `fetch_address_registry(chain_id).address("SupplyFuseAaveV3")` reads them by name (`ipor_fusion.registry`).
172
173
  A fuse must also be registered on the vault; `vault.get_fuses().call(ctx)` lists the registered ones.
173
174
 
174
175
  Amounts are raw on-chain integers (`Amount`, `Shares` in `ipor_fusion.types`); the SDK scales by decimals
@@ -225,6 +226,10 @@ fusion vault list
225
226
  # Inspect a Morpho Blue market or MetaMorpho vault
226
227
  fusion market morpho-blue 0xMARKET_ID --chain ethereum
227
228
  fusion market meta-morpho 0xVAULT_ADDRESS --chain ethereum
229
+
230
+ # Find IPOR Fusion contracts in the ipor-abi registry
231
+ fusion address lookup SupplyFuseAaveV3 --chain base
232
+ fusion address list --chain base
228
233
  ```
229
234
 
230
235
  ## MCP Server
@@ -291,6 +296,9 @@ Available tools:
291
296
  | `vault_remove` | Remove a vault from the local config |
292
297
  | `market_morpho_blue` | Morpho Blue market parameters and state |
293
298
  | `market_meta_morpho` | MetaMorpho V1 or Morpho Vault V2 allocations and caps (Morpho API) |
299
+ | `address_lookup` | IPOR Fusion contracts by name substring or address (ipor-abi registry) |
300
+ | `address_names` | Contract names in the registry, with the chains that have them |
301
+ | `address_list` | One chain's full `{name: address}` registry |
294
302
 
295
303
  Configure providers and vaults via `fusion config` or the MCP config tools first.
296
304
 
@@ -119,7 +119,8 @@ receipt = vault.execute([action]).send(ctx)
119
119
  ```
120
120
 
121
121
  Fuse, factory and manager addresses per chain are published in
122
- [ipor-abi](https://github.com/IPOR-Labs/ipor-abi) (`mainnet/mainnet-<chain>-fusion/addresses.json`).
122
+ [ipor-abi](https://github.com/IPOR-Labs/ipor-abi) (`mainnet/mainnet-<chain>-fusion/addresses.json`);
123
+ `fetch_address_registry(chain_id).address("SupplyFuseAaveV3")` reads them by name (`ipor_fusion.registry`).
123
124
  A fuse must also be registered on the vault; `vault.get_fuses().call(ctx)` lists the registered ones.
124
125
 
125
126
  Amounts are raw on-chain integers (`Amount`, `Shares` in `ipor_fusion.types`); the SDK scales by decimals
@@ -176,6 +177,10 @@ fusion vault list
176
177
  # Inspect a Morpho Blue market or MetaMorpho vault
177
178
  fusion market morpho-blue 0xMARKET_ID --chain ethereum
178
179
  fusion market meta-morpho 0xVAULT_ADDRESS --chain ethereum
180
+
181
+ # Find IPOR Fusion contracts in the ipor-abi registry
182
+ fusion address lookup SupplyFuseAaveV3 --chain base
183
+ fusion address list --chain base
179
184
  ```
180
185
 
181
186
  ## MCP Server
@@ -242,6 +247,9 @@ Available tools:
242
247
  | `vault_remove` | Remove a vault from the local config |
243
248
  | `market_morpho_blue` | Morpho Blue market parameters and state |
244
249
  | `market_meta_morpho` | MetaMorpho V1 or Morpho Vault V2 allocations and caps (Morpho API) |
250
+ | `address_lookup` | IPOR Fusion contracts by name substring or address (ipor-abi registry) |
251
+ | `address_names` | Contract names in the registry, with the chains that have them |
252
+ | `address_list` | One chain's full `{name: address}` registry |
245
253
 
246
254
  Configure providers and vaults via `fusion config` or the MCP config tools first.
247
255
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.0.0.dev274"
3
+ version = "4.0.0.dev282"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -231,9 +231,11 @@ slot was read on chain and matches the registry's `IporFusionFactoryImpl`;
231
231
  The factory implementations are upgraded in place, so the implementation
232
232
  column changes with releases while the proxy stays.
233
233
 
234
- Fuse addresses are not in the SDK. Resolve them by registry name and chain
235
- in `ipor-abi` (`SupplyFuseAaveV3`, `BalanceFuseAaveV3`, ...), or with the
236
- hosted server's `fusion_address_lookup(name, chain_id=...)`. The SDK class
234
+ Resolve fuse addresses by registry name and chain from `ipor-abi`
235
+ (`SupplyFuseAaveV3`, `BalanceFuseAaveV3`, ...):
236
+ `fetch_address_registry(ChainId(8453)).address("SupplyFuseAaveV3")` in the SDK,
237
+ `fusion address lookup SupplyFuseAaveV3 --chain base`, or the MCP tool
238
+ `address_lookup` (the hosted server's `fusion_address_lookup`). The SDK class
237
239
  for a registry name swaps the parts: `SupplyFuseAaveV3` is `AaveV3SupplyFuse`.
238
240
 
239
241
  ## Pointers
@@ -107,6 +107,8 @@ from ipor_fusion.dependency_graph import (
107
107
  )
108
108
  from ipor_fusion.errors import (
109
109
  CUSTOM_ERRORS,
110
+ AddressNotInRegistryError,
111
+ AddressRegistryError,
110
112
  BalanceSlotNotFoundError,
111
113
  ContractNotFoundError,
112
114
  CrosschainDiscoveryError,
@@ -301,6 +303,22 @@ from ipor_fusion.readers.oracle_mapping_nodes import (
301
303
  OraclePriceJson,
302
304
  SourceDetailJson,
303
305
  )
306
+ from ipor_fusion.registry import (
307
+ REGISTRY_CHAIN_IDS,
308
+ REGISTRY_REPOSITORY,
309
+ AddressListJson,
310
+ AddressLookupJson,
311
+ AddressMatchJson,
312
+ AddressNameJson,
313
+ AddressNamesJson,
314
+ AddressRegistry,
315
+ build_address_list_json,
316
+ build_address_lookup_json,
317
+ build_address_names_json,
318
+ fetch_address_registries,
319
+ fetch_address_registry,
320
+ registry_url,
321
+ )
304
322
  from ipor_fusion.substrates import (
305
323
  SubstrateInfo,
306
324
  decode_substrate,
@@ -450,6 +468,22 @@ __all__ = [
450
468
  "repository_url",
451
469
  "Web3Context",
452
470
  "InFlightLimit",
471
+ "AddressNotInRegistryError",
472
+ "AddressRegistryError",
473
+ "REGISTRY_CHAIN_IDS",
474
+ "REGISTRY_REPOSITORY",
475
+ "AddressListJson",
476
+ "AddressLookupJson",
477
+ "AddressMatchJson",
478
+ "AddressNameJson",
479
+ "AddressNamesJson",
480
+ "AddressRegistry",
481
+ "build_address_list_json",
482
+ "build_address_lookup_json",
483
+ "build_address_names_json",
484
+ "fetch_address_registries",
485
+ "fetch_address_registry",
486
+ "registry_url",
453
487
  "ContextManager",
454
488
  "Call",
455
489
  "get_logs_adaptive",
@@ -0,0 +1,108 @@
1
+ """`fusion address` — IPOR Fusion deployment addresses from the ipor-abi registry."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json as json_lib
6
+
7
+ import click
8
+
9
+ from ipor_fusion.cli.options import CHAIN
10
+ from ipor_fusion.cli.vault_rendering import _print_table
11
+ from ipor_fusion.errors import AddressRegistryError, UnsupportedChainError
12
+ from ipor_fusion.registry import (
13
+ AddressRegistry,
14
+ build_address_list_json,
15
+ build_address_lookup_json,
16
+ build_address_names_json,
17
+ fetch_address_registries,
18
+ fetch_address_registry,
19
+ )
20
+ from ipor_fusion.types import ChainId
21
+
22
+ _JSON = click.option(
23
+ "--json",
24
+ "json_output",
25
+ is_flag=True,
26
+ default=False,
27
+ help="Emit machine-readable JSON instead of a table.",
28
+ )
29
+
30
+
31
+ def _registries(chain_id: ChainId | None) -> list[AddressRegistry]:
32
+ try:
33
+ return fetch_address_registries(None if chain_id is None else [chain_id])
34
+ except (AddressRegistryError, UnsupportedChainError) as exc:
35
+ raise click.UsageError(str(exc)) from exc
36
+
37
+
38
+ @click.group()
39
+ def address() -> None:
40
+ """Look up IPOR Fusion contract addresses (ipor-abi registry)."""
41
+
42
+
43
+ @address.command("lookup")
44
+ @click.argument("query")
45
+ @click.option(
46
+ "--chain",
47
+ "chain_id",
48
+ type=CHAIN,
49
+ default=None,
50
+ help="Search one chain (ID or name); default: every chain with a registry.",
51
+ )
52
+ @_JSON
53
+ def lookup(query: str, chain_id: ChainId | None, json_output: bool) -> None:
54
+ """Find contracts by name substring, or the names of an address."""
55
+ document = build_address_lookup_json(query, _registries(chain_id))
56
+ if json_output:
57
+ click.echo(json_lib.dumps(document, indent=2))
58
+ return
59
+ _print_table(
60
+ ("Chain", "Name", "Address"),
61
+ [(m["chain"], m["name"], m["address"]) for m in document["matches"]],
62
+ )
63
+
64
+
65
+ @address.command("names")
66
+ @click.option(
67
+ "--chain",
68
+ "chain_id",
69
+ type=CHAIN,
70
+ default=None,
71
+ help="List one chain (ID or name); default: every chain with a registry.",
72
+ )
73
+ @_JSON
74
+ def names(chain_id: ChainId | None, json_output: bool) -> None:
75
+ """List the contract names in the registry, with the chains that have them."""
76
+ document = build_address_names_json(_registries(chain_id))
77
+ if json_output:
78
+ click.echo(json_lib.dumps(document, indent=2))
79
+ return
80
+ _print_table(
81
+ ("Name", "Chains"),
82
+ [
83
+ (entry["name"], ", ".join(str(c) for c in entry["chain_ids"]))
84
+ for entry in document["names"]
85
+ ],
86
+ )
87
+
88
+
89
+ @address.command("list")
90
+ @click.option(
91
+ "--chain",
92
+ "chain_id",
93
+ type=CHAIN,
94
+ required=True,
95
+ help="Chain ID or name (ethereum, base, arbitrum, ...).",
96
+ )
97
+ @_JSON
98
+ def list_addresses(chain_id: ChainId, json_output: bool) -> None:
99
+ """Every registered contract of one chain."""
100
+ try:
101
+ registry = fetch_address_registry(chain_id)
102
+ except (AddressRegistryError, UnsupportedChainError) as exc:
103
+ raise click.UsageError(str(exc)) from exc
104
+ document = build_address_list_json(registry)
105
+ if json_output:
106
+ click.echo(json_lib.dumps(document, indent=2))
107
+ return
108
+ _print_table(("Name", "Address"), list(document["addresses"].items()))
@@ -5,6 +5,7 @@ import sys
5
5
 
6
6
  import click
7
7
 
8
+ from ipor_fusion.cli.address_cmd import address
8
9
  from ipor_fusion.cli.changelog_cmd import changelog
9
10
  from ipor_fusion.cli.config_cmd import config
10
11
  from ipor_fusion.cli.market_cmd import market
@@ -29,6 +30,7 @@ def cli(ctx: click.Context, verbose: bool, quiet: bool, no_color: bool) -> None:
29
30
  ctx.obj["no_color"] = False
30
31
 
31
32
 
33
+ cli.add_command(address)
32
34
  cli.add_command(changelog)
33
35
  cli.add_command(config)
34
36
  cli.add_command(market)
@@ -293,6 +293,15 @@ class MorphoApiError(IporFusionError, RuntimeError):
293
293
  addresses or market ids). Also a RuntimeError, its base before 4.0."""
294
294
 
295
295
 
296
+ class AddressRegistryError(IporFusionError, RuntimeError):
297
+ """The ipor-abi address registry is unreachable or its file does not parse
298
+ as a ``{name: address}`` map."""
299
+
300
+
301
+ class AddressNotInRegistryError(IporFusionError, LookupError):
302
+ """A chain's address registry has no contract by the requested name."""
303
+
304
+
296
305
  class CrosschainDiscoveryError(IporFusionError):
297
306
  """A crosschain vault's on-chain configuration is not one discovery can
298
307
  use: a malformed or unexpected market grant, an executor managed by another
@@ -14,14 +14,18 @@ from ipor_fusion.types import Amount, FuseAddress
14
14
  class UniversalTokenSwapperAbi(Enum):
15
15
  """ABI revision of the deployed UniversalTokenSwapperFuse contract.
16
16
 
17
- Deployed fuses are immutable, so both revisions coexist across chains:
18
- older deployments (e.g. Base) accept only the LEGACY signature, newer
19
- ones (e.g. HyperEVM, markets 12 and 1202) only the MIN_AMOUNT_OUT one.
20
- Pick the member matching the fuse address this instance is bound to.
17
+ Deployed fuses are immutable, so the revisions coexist across chains:
18
+ older deployments (e.g. Base) accept only the LEGACY signature, the
19
+ HyperEVM ones (markets 12 and 1202) only the MIN_AMOUNT_OUT one, and the
20
+ Arbitrum fuses of the 2026-10-21 contracts release (markets 12 and 1202)
21
+ only TOKENS_TO_RETURN, which adds the tokens the swap calls may leave in
22
+ the executor. Pick the member matching the fuse address this instance is
23
+ bound to.
21
24
  """
22
25
 
23
26
  LEGACY = auto()
24
27
  MIN_AMOUNT_OUT = auto()
28
+ TOKENS_TO_RETURN = auto()
25
29
 
26
30
 
27
31
  class UniversalTokenSwapperSubstrates:
@@ -73,7 +77,11 @@ class UniversalTokenSwapperFuse(Fuse):
73
77
  targets: list[ChecksumAddress],
74
78
  data: list[bytes],
75
79
  min_amount_out: Amount | None = None,
80
+ tokens_to_return: list[ChecksumAddress] | None = None,
76
81
  ) -> FuseAction:
82
+ """``tokens_to_return`` (TOKENS_TO_RETURN only): intermediate or extra
83
+ output tokens the swap calls may leave in the executor, each a granted
84
+ Token substrate; the executor returns them to the vault."""
77
85
  self._validate_address(token_in, "token_in")
78
86
  self._validate_address(token_out, "token_out")
79
87
  self._validate_amount(amount_in, "amount_in")
@@ -81,6 +89,13 @@ class UniversalTokenSwapperFuse(Fuse):
81
89
  raise ValueError(
82
90
  f"targets and data must have the same length, got {len(targets)} and {len(data)}"
83
91
  )
92
+ if (
93
+ tokens_to_return is not None
94
+ and self._abi is not UniversalTokenSwapperAbi.TOKENS_TO_RETURN
95
+ ):
96
+ raise ValueError(
97
+ "tokens_to_return requires abi=UniversalTokenSwapperAbi.TOKENS_TO_RETURN"
98
+ )
84
99
  if self._abi is UniversalTokenSwapperAbi.LEGACY:
85
100
  if min_amount_out is not None:
86
101
  raise ValueError(
@@ -92,11 +107,27 @@ class UniversalTokenSwapperFuse(Fuse):
92
107
  )
93
108
  if min_amount_out is None:
94
109
  raise ValueError(
95
- "min_amount_out is required with abi=UniversalTokenSwapperAbi.MIN_AMOUNT_OUT"
110
+ f"min_amount_out is required with abi=UniversalTokenSwapperAbi.{self._abi.name}"
96
111
  " (pass 0 to rely on the vault-side slippage cap only)"
97
112
  )
98
113
  self._validate_non_negative(min_amount_out, "min_amount_out")
114
+ if self._abi is UniversalTokenSwapperAbi.MIN_AMOUNT_OUT:
115
+ return self._action_raw(
116
+ "enter((address,address,uint256,uint256,(address[],bytes[])))",
117
+ [[token_in, token_out, amount_in, min_amount_out, [targets, data]]],
118
+ )
119
+ returned = list(tokens_to_return or [])
120
+ for index, token in enumerate(returned):
121
+ self._validate_address(token, f"tokens_to_return[{index}]")
99
122
  return self._action_raw(
100
- "enter((address,address,uint256,uint256,(address[],bytes[])))",
101
- [[token_in, token_out, amount_in, min_amount_out, [targets, data]]],
123
+ "enter((address,address,uint256,uint256,(address[],bytes[],address[])))",
124
+ [
125
+ [
126
+ token_in,
127
+ token_out,
128
+ amount_in,
129
+ min_amount_out,
130
+ [targets, data, returned],
131
+ ]
132
+ ],
102
133
  )
@@ -146,7 +146,9 @@ slot was read on chain and matches the registry's `IporFusionFactoryImpl`;
146
146
  The factory implementations are upgraded in place, so the implementation
147
147
  column changes with releases while the proxy stays.
148
148
 
149
- Fuse addresses are not in the SDK. Resolve them by registry name and chain
150
- in `ipor-abi` (`SupplyFuseAaveV3`, `BalanceFuseAaveV3`, ...), or with the
151
- hosted server's `fusion_address_lookup(name, chain_id=...)`. The SDK class
149
+ Resolve fuse addresses by registry name and chain from `ipor-abi`
150
+ (`SupplyFuseAaveV3`, `BalanceFuseAaveV3`, ...):
151
+ `fetch_address_registry(ChainId(8453)).address("SupplyFuseAaveV3")` in the SDK,
152
+ `fusion address lookup SupplyFuseAaveV3 --chain base`, or the MCP tool
153
+ `address_lookup` (the hosted server's `fusion_address_lookup`). The SDK class
152
154
  for a registry name swaps the parts: `SupplyFuseAaveV3` is `AaveV3SupplyFuse`.
@@ -1199,3 +1199,44 @@ class ServerInfoResponse(_Base):
1199
1199
  "crosschain and HyperCore). Everything the package ships outside these "
1200
1200
  "is production.",
1201
1201
  )
1202
+
1203
+
1204
+ class AddressMatch(_Base):
1205
+ chain_id: ChainId
1206
+ chain: str
1207
+ name: str = Field(description="Contract name in the ipor-abi registry.")
1208
+ address: str
1209
+
1210
+
1211
+ class AddressLookupResponse(_Base):
1212
+ """Registry entries matching a name substring or an address."""
1213
+
1214
+ query: str
1215
+ query_type: Literal["address", "name"] = Field(
1216
+ description="'address' for 0x and 40 hex digits (exact match), else 'name' "
1217
+ "(case-insensitive substring)."
1218
+ )
1219
+ match_count: int
1220
+ matches: list[AddressMatch]
1221
+
1222
+
1223
+ class AddressName(_Base):
1224
+ name: str
1225
+ chain_ids: list[ChainId] = Field(description="Chains registering this name.")
1226
+
1227
+
1228
+ class AddressNamesResponse(_Base):
1229
+ """Every contract name in the registries read."""
1230
+
1231
+ chain_ids: list[ChainId] = Field(description="Chains whose registry was read.")
1232
+ names: list[AddressName]
1233
+
1234
+
1235
+ class AddressListResponse(_Base):
1236
+ """One chain's full ``{name: address}`` registry."""
1237
+
1238
+ chain_id: ChainId
1239
+ chain: str
1240
+ ref: str = Field(description="ipor-abi git ref the map was read at.")
1241
+ count: int
1242
+ addresses: dict[str, str]
@@ -38,6 +38,9 @@ from ipor_fusion.market_info import (
38
38
  from ipor_fusion.mcp.guide import register_guide
39
39
  from ipor_fusion.mcp.models import (
40
40
  ActionResult,
41
+ AddressListResponse,
42
+ AddressLookupResponse,
43
+ AddressNamesResponse,
41
44
  ChangelogEntryModel,
42
45
  ConfigShowResponse,
43
46
  MetaMorphoVaultResponse,
@@ -57,6 +60,13 @@ from ipor_fusion.morpho_api import (
57
60
  )
58
61
  from ipor_fusion.readers.morpho import MorphoReader, morpho_blue_address
59
62
  from ipor_fusion.readers.oracle_mapping import build_oracle_mapping
63
+ from ipor_fusion.registry import (
64
+ build_address_list_json,
65
+ build_address_lookup_json,
66
+ build_address_names_json,
67
+ fetch_address_registries,
68
+ fetch_address_registry,
69
+ )
60
70
  from ipor_fusion.types import (
61
71
  ChainId,
62
72
  PlasmaVaultAddress,
@@ -127,7 +137,9 @@ def _build_ctx(
127
137
  return ctx, block_number
128
138
 
129
139
 
130
- def _no_zero_sentinel(name: str) -> Callable[[object], object]:
140
+ def _no_zero_sentinel(
141
+ name: str, omitted: str | None = None
142
+ ) -> Callable[[object], object]:
131
143
  """Refuse 0 with an explicit message: clients built against the 3.x tools
132
144
  still send it meaning auto / latest, and reading it as block or chain 0
133
145
  would answer with genesis-block data instead of an error."""
@@ -136,7 +148,14 @@ def _no_zero_sentinel(name: str) -> Callable[[object], object]:
136
148
  if value == 0 and not isinstance(value, bool):
137
149
  raise ValueError(
138
150
  f"{name}=0 is not a sentinel any more: omit {name} for "
139
- + ("the latest block" if name == "block_number" else "auto-detection")
151
+ + (
152
+ omitted
153
+ or (
154
+ "the latest block"
155
+ if name == "block_number"
156
+ else "auto-detection"
157
+ )
158
+ )
140
159
  )
141
160
  return value
142
161
 
@@ -158,6 +177,11 @@ ChainArg = Annotated[
158
177
 
159
178
  # The market tools need the chain: no auto-detection, so no omission either.
160
179
  RequiredChainArg = Annotated[ChainId, Field(description="Chain ID.", gt=0)]
180
+ RegistryChainArg = Annotated[
181
+ ChainId | None,
182
+ Field(description="Chain ID; omitted: every chain with a deployment file.", gt=0),
183
+ BeforeValidator(_no_zero_sentinel("chain_id", "every chain")),
184
+ ]
161
185
  BlockArg = Annotated[
162
186
  int | None,
163
187
  Field(description="Block number (positive); omitted: latest.", ge=1),
@@ -681,6 +705,35 @@ def market_meta_morpho(
681
705
  return MetaMorphoVaultResponse.model_validate(payload)
682
706
 
683
707
 
708
+ @mcp.tool()
709
+ def address_lookup(
710
+ query: str, chain_id: RegistryChainArg = None
711
+ ) -> AddressLookupResponse:
712
+ """Find IPOR Fusion contracts in the ipor-abi registry by name substring, or
713
+ the names of an address. Reads one file per chain (cached ten minutes)."""
714
+ registries = fetch_address_registries(None if chain_id is None else [chain_id])
715
+ return AddressLookupResponse.model_validate(
716
+ build_address_lookup_json(query, registries)
717
+ )
718
+
719
+
720
+ @mcp.tool()
721
+ def address_names(chain_id: RegistryChainArg = None) -> AddressNamesResponse:
722
+ """List the contract names in the ipor-abi registry, with the chains that
723
+ have each; use them with address_lookup."""
724
+ registries = fetch_address_registries(None if chain_id is None else [chain_id])
725
+ return AddressNamesResponse.model_validate(build_address_names_json(registries))
726
+
727
+
728
+ @mcp.tool()
729
+ def address_list(chain_id: RequiredChainArg) -> AddressListResponse:
730
+ """One chain's full {name: address} registry: hundreds of entries;
731
+ address_lookup is cheaper for one contract."""
732
+ return AddressListResponse.model_validate(
733
+ build_address_list_json(fetch_address_registry(chain_id))
734
+ )
735
+
736
+
684
737
  def main() -> None:
685
738
  mcp.run(transport="stdio")
686
739