ipor-fusion 4.0.0.dev244__tar.gz → 4.0.0.dev249__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 (342) hide show
  1. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/MIGRATION_4.md +45 -27
  2. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/PKG-INFO +3 -2
  3. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/README.md +2 -1
  4. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/pyproject.toml +1 -1
  5. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/mcp/server.py +16 -9
  6. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_mcp_server.py +76 -0
  7. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.claude-plugin/marketplace.json +0 -0
  8. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.claude-plugin/plugin.json +0 -0
  9. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.env.example +0 -0
  10. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.gemini/settings.json +0 -0
  11. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.git-blame-ignore-revs +0 -0
  12. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.github/workflows/cd.yml +0 -0
  13. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.github/workflows/ci.yml +0 -0
  14. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.github/workflows/commit-lint.yml +0 -0
  15. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.github/workflows/notify-slack.yml +0 -0
  16. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.github/workflows/python-build.yml +0 -0
  17. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.github/workflows/python-publish.yml +0 -0
  18. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.github/workflows/release.yml +0 -0
  19. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.github/workflows/report-slack.yml +0 -0
  20. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.gitignore +0 -0
  21. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.mcp.json +0 -0
  22. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.pre-commit-config.yaml +0 -0
  23. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/.python-version +0 -0
  24. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/AGENTS.md +0 -0
  25. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/CHANGELOG.md +0 -0
  26. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/CLAUDE.md +0 -0
  27. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/CODEOWNERS +0 -0
  28. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/LICENSE +0 -0
  29. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/build.sh +0 -0
  30. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/examples/CONTRIBUTING.md +0 -0
  31. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/examples/README.md +0 -0
  32. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  33. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  34. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  35. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  36. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/examples/external_state_margin_leg_base.py +0 -0
  37. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/examples/simple_aave_v3_supply_base.py +0 -0
  38. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/pytest.ini +0 -0
  39. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/scripts/commit-check.sh +0 -0
  40. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/scripts/crosschain_readiness.py +0 -0
  41. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/skills/ipor-deploy-vault/SKILL.md +0 -0
  42. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/__init__.py +0 -0
  43. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/about.py +0 -0
  44. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cache.py +0 -0
  45. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/chains.py +0 -0
  46. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/__init__.py +0 -0
  47. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  48. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/config_cmd.py +0 -0
  49. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/config_store.py +0 -0
  50. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/main.py +0 -0
  51. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/market_cmd.py +0 -0
  52. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/options.py +0 -0
  53. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  54. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  55. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_health.py +0 -0
  56. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  57. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  58. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  59. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/config/__init__.py +0 -0
  60. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/config/roles.py +0 -0
  61. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/__init__.py +0 -0
  62. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/access.py +0 -0
  63. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/address.py +0 -0
  64. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/context.py +0 -0
  65. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/contract.py +0 -0
  66. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/erc20.py +0 -0
  67. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/external_state_executor.py +0 -0
  68. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/fee_manager.py +0 -0
  69. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/fuse.py +0 -0
  70. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/fuse_action.py +0 -0
  71. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/fusion_factory.py +0 -0
  72. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/logs.py +0 -0
  73. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/multicall.py +0 -0
  74. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/oracle.py +0 -0
  75. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/plasma_vault.py +0 -0
  76. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/rewards_manager.py +0 -0
  77. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/simulation.py +0 -0
  78. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/simulation_result.py +0 -0
  79. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  80. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/__init__.py +0 -0
  81. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  82. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  83. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  84. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  85. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  86. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  87. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  88. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  89. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  90. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/contracts.py +0 -0
  91. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/discovery.py +0 -0
  92. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/errors.py +0 -0
  93. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  94. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  95. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  96. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  97. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/lane.py +0 -0
  98. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/logs.py +0 -0
  99. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/messages.py +0 -0
  100. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/simulation.py +0 -0
  101. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  102. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  103. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  104. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  105. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  106. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/transport.py +0 -0
  107. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/dependency_graph.py +0 -0
  108. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/entry_cli.py +0 -0
  109. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/entry_mcp.py +0 -0
  110. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/errors.py +0 -0
  111. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/explorer.py +0 -0
  112. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/field_docs.py +0 -0
  113. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/__init__.py +0 -0
  114. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  115. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/async_action.py +0 -0
  116. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/base.py +0 -0
  117. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  118. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/erc4626.py +0 -0
  119. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  120. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/events.py +0 -0
  121. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/external_state.py +0 -0
  122. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
  123. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  124. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  125. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/hypercore.py +0 -0
  126. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
  127. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/merkl.py +0 -0
  128. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/morpho.py +0 -0
  129. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  130. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  131. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/universal.py +0 -0
  132. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/__init__.py +0 -0
  133. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/architecture.md +0 -0
  134. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/glossary.md +0 -0
  135. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/invariants.md +0 -0
  136. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/quickstart.md +0 -0
  137. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/hypercore/__init__.py +0 -0
  138. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/market_ids.py +0 -0
  139. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/market_info.py +0 -0
  140. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/mcp/__init__.py +0 -0
  141. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/mcp/guide.py +0 -0
  142. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/mcp/models.py +0 -0
  143. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/morpho_api.py +0 -0
  144. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/py.typed +0 -0
  145. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/__init__.py +0 -0
  146. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/aave_v3.py +0 -0
  147. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/aave_v4.py +0 -0
  148. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/compound_v3.py +0 -0
  149. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/hypercore.py +0 -0
  150. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  151. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/lending_health.py +0 -0
  152. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/morpho.py +0 -0
  153. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  154. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
  155. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  156. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/position_manager.py +0 -0
  157. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  158. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  159. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/unpriceable.py +0 -0
  160. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/substrates.py +0 -0
  161. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/types.py +0 -0
  162. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/validation.py +0 -0
  163. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_data.py +0 -0
  164. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_erc20.py +0 -0
  165. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_info.py +0 -0
  166. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_managers.py +0 -0
  167. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_positions.py +0 -0
  168. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_reads.py +0 -0
  169. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/UniswapV3UniversalRouter.py +0 -0
  170. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_crosschain.py +0 -0
  171. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_crosschain_lifecycle.py +0 -0
  172. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_crosschain_recovery.py +0 -0
  173. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_euler_v2.py +0 -0
  174. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_event_args.py +0 -0
  175. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_fake_rpc.py +0 -0
  176. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_foundry.py +0 -0
  177. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_golden.py +0 -0
  178. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_guide.py +0 -0
  179. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_hypercore_model.py +0 -0
  180. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_hypercore_shadow.py +0 -0
  181. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_live.py +0 -0
  182. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_multicall.py +0 -0
  183. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_oracle_mapping_fake.py +0 -0
  184. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_simulate.py +0 -0
  185. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/_validation.py +0 -0
  186. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/addresses.py +0 -0
  187. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/conftest.py +0 -0
  188. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/constants.py +0 -0
  189. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  190. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/hypercore_market55.json +0 -0
  191. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
  192. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
  193. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
  194. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
  195. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
  196. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
  197. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
  198. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
  199. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue.json +0 -0
  200. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
  201. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
  202. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
  203. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
  204. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
  205. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
  206. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
  207. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/simulate_v1_request.json +0 -0
  208. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/clean.json +0 -0
  209. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
  210. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  211. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
  212. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
  213. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
  214. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
  215. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/fetched.json +0 -0
  216. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
  217. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/full.json +0 -0
  218. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
  219. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/full.txt +0 -0
  220. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/rich.json +0 -0
  221. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
  222. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  223. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_about.py +0 -0
  224. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_access_manager.py +0 -0
  225. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cache.py +0 -0
  226. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_chains.py +0 -0
  227. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_changelog.py +0 -0
  228. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_commands.py +0 -0
  229. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_config_store.py +0 -0
  230. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_helpers.py +0 -0
  231. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_hypercore.py +0 -0
  232. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_lending_health.py +0 -0
  233. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_market_golden.py +0 -0
  234. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_market_morpho_blue.py +0 -0
  235. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_mcp_parity.py +0 -0
  236. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_oracle_mapping.py +0 -0
  237. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_oracle_mapping_golden.py +0 -0
  238. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_pending_requests_scan.py +0 -0
  239. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_role_accounts.py +0 -0
  240. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_vault_info_golden.py +0 -0
  241. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_vault_predates_getters.py +0 -0
  242. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_cli_vault_validate.py +0 -0
  243. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_contract_call.py +0 -0
  244. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_contract_encoder.py +0 -0
  245. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_ccip_events.py +0 -0
  246. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_ccip_indexer.py +0 -0
  247. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_ccip_quote.py +0 -0
  248. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_chainlink.py +0 -0
  249. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_contracts.py +0 -0
  250. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_encoding.py +0 -0
  251. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_errors.py +0 -0
  252. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_lane.py +0 -0
  253. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_layering.py +0 -0
  254. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_readiness.py +0 -0
  255. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_readiness_report.py +0 -0
  256. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_transport.py +0 -0
  257. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_docs_typing.py +0 -0
  258. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_erc20.py +0 -0
  259. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_error_hierarchy.py +0 -0
  260. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_examples_composed_hypercore.py +0 -0
  261. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_examples_crosschain.py +0 -0
  262. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  263. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_examples_vaults.py +0 -0
  264. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_explorer.py +0 -0
  265. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_external_state_events.py +0 -0
  266. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_external_state_executor.py +0 -0
  267. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_fee_manager.py +0 -0
  268. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_fuse_encoding.py +0 -0
  269. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_fusion_instance.py +0 -0
  270. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_guide.py +0 -0
  271. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_deployment.py +0 -0
  272. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_events.py +0 -0
  273. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_flow.py +0 -0
  274. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_live.py +0 -0
  275. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_outcome.py +0 -0
  276. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_readers.py +0 -0
  277. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_simulation.py +0 -0
  278. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_logs.py +0 -0
  279. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_mcp_hypercore.py +0 -0
  280. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_mcp_models.py +0 -0
  281. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_mcp_vault_validate.py +0 -0
  282. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_multicall.py +0 -0
  283. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_oracle.py +0 -0
  284. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_oracle_mapping.py +0 -0
  285. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_plasma_vault.py +0 -0
  286. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_public_api.py +0 -0
  287. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_public_type_reachability.py +0 -0
  288. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_reader_encoding.py +0 -0
  289. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_readiness_selection.py +0 -0
  290. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_revert_decoding.py +0 -0
  291. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_rewards_manager.py +0 -0
  292. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_roles.py +0 -0
  293. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_sdk_layering.py +0 -0
  294. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  295. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  296. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  297. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_crosschain_canary.py +0 -0
  298. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_crosschain_hypercore.py +0 -0
  299. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  300. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  301. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  302. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  303. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  304. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  305. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  306. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_examples_arbitrum.py +0 -0
  307. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_examples_base.py +0 -0
  308. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_examples_crosschain.py +0 -0
  309. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_external_state_executor_base.py +0 -0
  310. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  311. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  312. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  313. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_morpho_blue.py +0 -0
  314. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_pilot_v3.py +0 -0
  315. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  316. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  317. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  318. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  319. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_readers_integration.py +0 -0
  320. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_release_funds.py +0 -0
  321. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_swap_on_base.py +0 -0
  322. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  323. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulation_errors.py +0 -0
  324. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_simulation_observation.py +0 -0
  325. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_solidity_compiler.py +0 -0
  326. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_solidity_mirrors.py +0 -0
  327. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_substrates.py +0 -0
  328. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_types_and_events.py +0 -0
  329. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_unpriceable_tokens.py +0 -0
  330. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_validation.py +0 -0
  331. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_vault_data_block.py +0 -0
  332. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_vault_dep_graph.py +0 -0
  333. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_vault_info_fetched_golden.py +0 -0
  334. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_vault_info_onchain_base.py +0 -0
  335. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  336. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_vault_reconciliation_onchain_base.py +0 -0
  337. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_vault_simulator_blocks.py +0 -0
  338. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_web3_context.py +0 -0
  339. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/test_withdraw_manager.py +0 -0
  340. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/typed_client/consumer.py +0 -0
  341. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/tests/typed_client/rejected.py +0 -0
  342. {ipor_fusion-4.0.0.dev244 → ipor_fusion-4.0.0.dev249}/uv.lock +0 -0
@@ -20,8 +20,9 @@ the details, and each change is described once, in its section.
20
20
  > checker cannot see the calls made through them;
21
21
  > - run the reads against a provider, not only the test suite.
22
22
 
23
- Work through these in order; each is what breaks first at run time after the one
24
- before it is fixed.
23
+ Work through these in order. Removed imports fail first, at import; the rest is
24
+ the recommended order, roughly what fails next at run time (a positional option
25
+ such as `Web3Context.from_url(url, key)` can fail before any wrapper is built).
25
26
 
26
27
  1. **Removed and renamed imports fail first, at import.** The preview features
27
28
  left the top level: crosschain names import from `ipor_fusion.crosschain`,
@@ -47,8 +48,9 @@ before it is fixed.
47
48
  raises `AttributeError`. See [Vault reads and validation](#vault-reads-and-validation).
48
49
  5. **The vault read is one snapshot.** `fetch_vault_data(ctx, vault, *, block=None,
49
50
  lending=True, metadata=True)` takes the vault address and the chain from `ctx`;
50
- `validate_vault_state(state)` and `build_vault_info_json(data, *,
51
- resolve_name=None)` are pure. See [Vault reads and validation](#vault-reads-and-validation).
51
+ `validate_vault_state(state)` reads nothing, and `build_vault_info_json(data, *,
52
+ resolve_name=None)` reads no vault state (contract names come from
53
+ `resolve_name`, the deployment age from the wall clock). See [Vault reads and validation](#vault-reads-and-validation).
52
54
  6. **Simulations return typed observations.** `sim.observe("label", call)` raises
53
55
  `TypeError`: `read = sim.observe(call, label="label")` returns a
54
56
  `SimulationObservation`, read as `read.value` after `run()`;
@@ -282,7 +284,8 @@ The vault read is one pinned snapshot, and the chain is always the context's:
282
284
  `VaultState` also provides `vault`, `chain_id`, `market_balances`, `erc20` and the
283
285
  queue's `shares_to_release_assets`.
284
286
  - `build_vault_info_json(data, *, resolve_name=None)` renders from the snapshot and
285
- reads nothing; the chain and its label come from `data.chain_id`. Without
287
+ reads no vault state (`resolve_name`, which may look names up, and the deployment
288
+ age, computed from the wall clock, are its only other inputs); the chain and its label come from `data.chain_id`. Without
286
289
  `resolve_name` it names no contract (see
287
290
  [Contract cache and request limit](#contract-cache-and-request-limit)).
288
291
  - `fetch_deployment_info(ctx, vault, *, api_key=None)` and
@@ -301,14 +304,16 @@ The vault read is one pinned snapshot, and the chain is always the context's:
301
304
 
302
305
  **Public API.** 4.0 declares it: `ipor_fusion.__all__`, which now also exports the
303
306
  names earlier reachable only by module path (`FusionFactory`, `FusionInstance`,
304
- `fetch_market`, `resolve_token_symbol`, the crosschain codecs, ...). Import from
307
+ `fetch_market`, `resolve_token_symbol`, ...); the preview features are exported only
308
+ from their subpackages (see below). Import from
305
309
  `ipor_fusion`: a module path outside the README's list (*Public API and stability*)
306
310
  still works but is internal. Every project type a public signature or field uses is
307
311
  exported too, among them `AaveV3PositionBreakdown`, `AaveV3ReserveTokens`,
308
- `AccountRequest`, `StateOverrideProvider`, `TransferDirection` and the validation
312
+ `AccountRequest`, `StateOverrideProvider` and the validation
309
313
  vocabulary `Severity`, `Verdict` and `Check`. Also new: `InFlightLimit` (see
310
- [Contract cache and request limit](#contract-cache-and-request-limit)) and
311
- `log_bytes`, the hex-or-bytes log field helper the crosschain decoders use.
314
+ [Contract cache and request limit](#contract-cache-and-request-limit)), and in
315
+ `ipor_fusion.crosschain` `log_bytes`, the hex-or-bytes log field helper the
316
+ crosschain decoders use.
312
317
 
313
318
  **Crosschain fuse encoders moved.** The crosschain market encoders moved from
314
319
  `ipor_fusion.fuses.crosschain` into the crosschain package, and
@@ -391,9 +396,9 @@ the modules are internal.
391
396
  - `MORPHO_BLUE_ADDRESS`: use `morpho_blue_address(chain_id)`. `BLOCK_EXPLORER_URLS`,
392
397
  `MORPHO_BLUE_ADDRESSES`, `AAVE_V3_POOL` and `explorer.SUPPORTED_CHAINS` are
393
398
  internal. Import `CHAIN_NAMES`, `CHAIN_NAME_TO_ID`, `SUPPORTED_CHAIN_IDS`,
394
- `GET_LOGS_RANGE_HINTS`, `PUBLIC_ALLOCATOR_ADDRESSES`, `HYPERCORE_PENDING_READERS`,
395
- `HYPEREVM_CHAIN_ID` and `HYPERCORE_MARKET` from `ipor_fusion` (the HyperCore ones
396
- also from `ipor_fusion.readers`).
399
+ `GET_LOGS_RANGE_HINTS`, `PUBLIC_ALLOCATOR_ADDRESSES` and `HYPEREVM_CHAIN_ID` from
400
+ `ipor_fusion` (`HYPEREVM_CHAIN_ID` also from `ipor_fusion.readers`), and
401
+ `HYPERCORE_PENDING_READERS` and `HYPERCORE_MARKET` from `ipor_fusion.hypercore`.
397
402
  - `read_erc20_holdings`: the holdings are `VaultData.erc20`.
398
403
  - `ExternalStateExecutor.mark_nav` and `NavMark`: send `propose_balance` and
399
404
  `confirm_balance` from separate custodians, then
@@ -626,7 +631,10 @@ typed client with pyright's `reportArgumentType`. Other fields keep their types
626
631
  the SDK returns already carry their type and go back in unwrapped.
627
632
 
628
633
  The SDK's own types are importable from `ipor_fusion` (and the public module
629
- `ipor_fusion.types`), as are `USDC_TOKEN_INDEX` and `hip3_action_asset`. Third-party
634
+ `ipor_fusion.types`), except the preview features' ids, which come from their
635
+ subpackages: the crosschain ids (`CommandId`, ...) from `ipor_fusion.crosschain`, the
636
+ HyperCore ids (`HyperCoreAsset`, ...), `USDC_TOKEN_INDEX` and `hip3_action_asset`
637
+ from `ipor_fusion.hypercore`. Third-party
630
638
  types are not re-exported: `ChecksumAddress` and `HexAddress` come from `eth_typing`,
631
639
  and `BlockIdentifier`, `Timestamp` and `TxParams` from `web3.types`. The wrappers
632
640
  label values; they do not validate byte widths or address spelling.
@@ -890,8 +898,10 @@ oracle node's `source_detail`, the Morpho `asset`, `adapters`, `caps`,
890
898
  ## Typed JSON documents
891
899
 
892
900
  The JSON document builders return `TypedDict`s instead of `dict[str, Any]`; the
893
- documents themselves (keys, values, order, the MCP schemas) are unchanged, so
894
- untyped code needs none of this section.
901
+ typing itself changes no document (keys, values, order); the documents' own 4.0
902
+ changes are listed under [Behavior changes](#behavior-changes) (the validation
903
+ document, reconciliation and lending-health fields, MCP null keys, addresses,
904
+ supply cap).
895
905
 
896
906
  | Builder | Returns |
897
907
  |---|---|
@@ -968,8 +978,9 @@ class. An event's args TypedDict is its class's `args` annotation:
968
978
  `typing.get_type_hints(EXTERNAL_STATE_EVENT_CLASSES[name])["args"]`. Values carry
969
979
  nominal types (`Amount`, `MarketId`, `FuseAddress`, `HyperCoreTokenIndex`,
970
980
  `PayloadHash`, web3's `Timestamp`, ...), and `HyperCoreEvent.fuse` is a
971
- `FuseAddress | None` on every event. Every name is importable from `ipor_fusion` and
972
- from `ipor_fusion.fuses`.
981
+ `FuseAddress | None` on every event. The ExternalState names are importable from
982
+ `ipor_fusion` and `ipor_fusion.fuses`; the HyperCore ones (preview) only from
983
+ `ipor_fusion.hypercore`.
973
984
 
974
985
  The two families share one input contract. `decode_external_state_event(log)` and
975
986
  `decode_hypercore_event(log)` take a web3 receipt log or a raw JSON-RPC / indexer
@@ -991,15 +1002,20 @@ These apply to every caller, type-checked or not. Changes described in full abov
991
1002
  are listed with a link.
992
1003
 
993
1004
  - **The CLI and the MCP tools take the same arguments.**
994
- - **MCP inputs:** `chain_id` and `block_number` are optional and omitted means
995
- auto-detected / latest. The `0` sentinel is gone, and `0` is now rejected with
996
- an error naming the argument to omit (it is never read as chain or block 0);
997
- a client that passed `0` must omit the argument instead. The CLI refuses
998
- `--block-number 0` and `--chain-id 0` the same way. `server_info(changelog_since=)` is `server_info(since=)` as in
1005
+ - **MCP inputs:** the vault tools' `chain_id` and every `block_number` are
1006
+ optional and omitted means auto-detected / latest; `market_morpho_blue` and
1007
+ `market_meta_morpho` still require a positive `chain_id`. The `0` sentinel is
1008
+ gone: an optional `0` is rejected with an error naming the argument to omit (it
1009
+ is never read as chain or block 0), so a client that passed `0` omits the
1010
+ argument instead; the market tools' required `chain_id` rejects `0` too and
1011
+ needs the real chain id. The CLI refuses `--block-number 0` and `--chain-id 0`
1012
+ the same way. `server_info(changelog_since=)` is `server_info(since=)` as in
999
1013
  `fusion changelog --since`, and `vault_oracle_mapping` takes `max_depth` like
1000
1014
  `--max-depth`.
1001
- - **Chain auto-detection:** both surfaces use the saved vault's chain, else the
1002
- chain of the only configured provider. The CLI used only the saved vault.
1015
+ - **Chain auto-detection:** the vault commands and tools use the saved vault's
1016
+ chain, else the chain of the only configured provider (the CLI used only the
1017
+ saved vault); `vault_add` uses the only configured provider, and
1018
+ `config_set_provider` asks the provider (`eth_chainId`).
1003
1019
  - **CLI options:** every `--block-number` rejects a negative block, and
1004
1020
  `fusion market morpho-blue --block` is `--block-number` (`--block` still
1005
1021
  works).
@@ -1104,8 +1120,8 @@ are listed with a link.
1104
1120
  and small or empty markets could be off by orders of magnitude: expect materially
1105
1121
  different numbers where they were wrong.
1106
1122
 
1107
- - **MCP `outputSchema` describes every nested block.** The tool output is
1108
- byte-identical; the schemas of `vault_info`, `vault_oracle_mapping`,
1123
+ - **MCP `outputSchema` describes every nested block.** This change alone keeps the
1124
+ tool output byte-identical (the other changes in this list still apply); the schemas of `vault_info`, `vault_oracle_mapping`,
1109
1125
  `market_morpho_blue` and `market_meta_morpho` replace each free-form object with
1110
1126
  the block's own definition: `links` (`VaultLinks`), `deployment`
1111
1127
  (`DeploymentModel` or `DeploymentErrorModel`), `share_price` (`SharePriceModel`),
@@ -1192,4 +1208,6 @@ are listed with a link.
1192
1208
  Both stay unhashable (`__hash__` is `None`, as before). The freeze is shallow:
1193
1209
  the `logs` / `calls` lists themselves can still be mutated.
1194
1210
  - Saved config entries are checksummed when loaded; the MCP `vault_add` tool rejects
1195
- a value that is not an address.
1211
+ a value that is not an address. The MCP vault tools accept a vault address as 3.x
1212
+ did (any letter case, with or without `0x`, surrounding whitespace) and normalize
1213
+ it before the strict SDK parser; only the SDK's `parse_*` functions are strict.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev244
3
+ Version: 4.0.0.dev249
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
@@ -412,7 +412,8 @@ release; adding one does not.
412
412
  - **Third-party types** are not re-exported: import `ChecksumAddress` and
413
413
  `HexAddress` from `eth_typing`, and `BlockIdentifier`, `Timestamp` and `TxParams`
414
414
  from `web3.types`. The SDK's own types (`ChainId`, `Amount`, `PlasmaVaultAddress`,
415
- ...) come from `ipor_fusion` or `ipor_fusion.types`.
415
+ ...) come from `ipor_fusion` or `ipor_fusion.types`; a preview feature's ids
416
+ (`CommandId`, `HyperCoreAsset`, ...) come from its subpackage.
416
417
 
417
418
  `tests/test_public_api.py` snapshots every `__all__` and the names each public
418
419
  module keeps by path, so a change to the surface is a deliberate, reviewed edit.
@@ -364,7 +364,8 @@ release; adding one does not.
364
364
  - **Third-party types** are not re-exported: import `ChecksumAddress` and
365
365
  `HexAddress` from `eth_typing`, and `BlockIdentifier`, `Timestamp` and `TxParams`
366
366
  from `web3.types`. The SDK's own types (`ChainId`, `Amount`, `PlasmaVaultAddress`,
367
- ...) come from `ipor_fusion` or `ipor_fusion.types`.
367
+ ...) come from `ipor_fusion` or `ipor_fusion.types`; a preview feature's ids
368
+ (`CommandId`, `HyperCoreAsset`, ...) come from its subpackage.
368
369
 
369
370
  `tests/test_public_api.py` snapshots every `__all__` and the names each public
370
371
  module keeps by path, so a change to the surface is a deliberate, reviewed edit.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.0.0.dev244"
3
+ version = "4.0.0.dev249"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -59,6 +59,7 @@ from ipor_fusion.readers.morpho import MorphoReader, morpho_blue_address
59
59
  from ipor_fusion.readers.oracle_mapping import build_oracle_mapping
60
60
  from ipor_fusion.types import (
61
61
  ChainId,
62
+ PlasmaVaultAddress,
62
63
  parse_morpho_market_id,
63
64
  parse_plasma_vault_address,
64
65
  )
@@ -100,6 +101,12 @@ def _resolve_provider(cfg: FusionConfig, chain_id: ChainId) -> str:
100
101
  )
101
102
 
102
103
 
104
+ def _vault_arg(raw: str) -> PlasmaVaultAddress:
105
+ """A vault address as a tool caller sends it: surrounding whitespace, a
106
+ missing ``0x`` and any letter case are accepted, as in 3.x."""
107
+ return parse_plasma_vault_address(Web3.to_checksum_address(raw.strip()))
108
+
109
+
103
110
  def _resolve_chain_id(
104
111
  cfg: FusionConfig, vault_address: str, chain_id: ChainId | None
105
112
  ) -> ChainId:
@@ -210,12 +217,12 @@ def vault_info(
210
217
  etc.).
211
218
  """
212
219
  cfg = load_config()
213
- chain_id = _resolve_chain_id(cfg, vault_address, chain_id)
220
+ checksum = _vault_arg(vault_address)
221
+ chain_id = _resolve_chain_id(cfg, checksum, chain_id)
214
222
  # Fail fast (before any RPC) on chains the vault tooling can't handle;
215
223
  # UnsupportedChainError doubles as ValueError so FastMCP surfaces it.
216
224
  ensure_supported_chain(chain_id)
217
225
  ctx, effective_block = _build_ctx(cfg, chain_id, block_number)
218
- checksum = parse_plasma_vault_address(vault_address)
219
226
 
220
227
  # Cheap single-call probe: raises the typed ContractNotFoundError /
221
228
  # NotPlasmaVaultError ("not a vault" in both revert and empty-return
@@ -257,10 +264,10 @@ def vault_validate(
257
264
  consistent. It reads about as much as vault_info and takes about as long.
258
265
  """
259
266
  cfg = load_config()
260
- chain_id = _resolve_chain_id(cfg, vault_address, chain_id)
267
+ checksum = _vault_arg(vault_address)
268
+ chain_id = _resolve_chain_id(cfg, checksum, chain_id)
261
269
  ensure_supported_chain(chain_id)
262
270
  ctx, effective_block = _build_ctx(cfg, chain_id, block_number)
263
- checksum = parse_plasma_vault_address(vault_address)
264
271
 
265
272
  # Same cheap probe as vault_info: "not a vault" fails before the fetch.
266
273
  resolve_access_manager(ctx, checksum)
@@ -323,12 +330,12 @@ def vault_role_accounts(
323
330
  """
324
331
  cfg = load_config()
325
332
  role_id = None if role is None else Roles.resolve(role)
326
- chain_id = _resolve_chain_id(cfg, vault_address, chain_id)
333
+ checksum = _vault_arg(vault_address)
334
+ chain_id = _resolve_chain_id(cfg, checksum, chain_id)
327
335
  # Fail fast (before any RPC) on chains the vault tooling is not
328
336
  # validated on.
329
337
  ensure_supported_chain(chain_id)
330
338
  ctx, _ = _build_ctx(cfg, chain_id, block_number)
331
- checksum = parse_plasma_vault_address(vault_address)
332
339
 
333
340
  access_manager = resolve_access_manager(ctx, checksum)
334
341
  accounts = (
@@ -408,12 +415,12 @@ def vault_oracle_mapping(
408
415
  'events'). Historical blocks require an archive node.
409
416
  """
410
417
  cfg = load_config()
411
- chain_id = _resolve_chain_id(cfg, vault_address, chain_id)
418
+ checksum = _vault_arg(vault_address)
419
+ chain_id = _resolve_chain_id(cfg, checksum, chain_id)
412
420
  # The asset-source event replay scans logs from block 0 — fail fast
413
421
  # (before any RPC) on chains the vault tooling is not validated on.
414
422
  ensure_supported_chain(chain_id)
415
423
  ctx, _ = _build_ctx(cfg, chain_id, block_number)
416
- checksum = parse_plasma_vault_address(vault_address)
417
424
 
418
425
  # The event-replay fallback and the output both need a concrete block
419
426
  # number, so resolve "latest" up front and pin the context to it.
@@ -464,7 +471,7 @@ def vault_add(
464
471
  address: Vault address (required).
465
472
  label: Human-readable label (fetched from on-chain name() if empty).
466
473
  """
467
- checksum = parse_plasma_vault_address(address)
474
+ checksum = _vault_arg(address)
468
475
  cfg = load_config()
469
476
 
470
477
  if chain_id is None:
@@ -26,6 +26,7 @@ from ipor_fusion.mcp.models import (
26
26
  WithdrawManagerDetails,
27
27
  )
28
28
  from ipor_fusion.mcp.server import (
29
+ _vault_arg,
29
30
  config_set_etherscan_key,
30
31
  config_set_provider,
31
32
  config_show,
@@ -39,6 +40,7 @@ from ipor_fusion.mcp.server import (
39
40
  vault_oracle_mapping,
40
41
  vault_remove,
41
42
  vault_role_accounts,
43
+ vault_validate,
42
44
  )
43
45
  from ipor_fusion.morpho_api import (
44
46
  MorphoApiError,
@@ -1082,3 +1084,77 @@ class TestMarketMetaMorpho:
1082
1084
  def test_unknown_vault_errors(self, _fetch):
1083
1085
  with pytest.raises(MorphoApiError, match="not found"):
1084
1086
  market_meta_morpho(vault_address=_VAULT, chain_id=1)
1087
+
1088
+
1089
+ class TestVaultAddressArgument:
1090
+ """Tool callers send addresses as 3.x accepted them; the server normalizes
1091
+ before the strict SDK parser."""
1092
+
1093
+ VAULT = "0x43ee0243ea8cf02f7087d8b16c8d2007cc9c7ca2"
1094
+
1095
+ @pytest.mark.parametrize(
1096
+ "raw",
1097
+ [
1098
+ VAULT,
1099
+ VAULT.upper().replace("0X", "0x"),
1100
+ VAULT[2:],
1101
+ f" {VAULT} ",
1102
+ Web3.to_checksum_address(VAULT),
1103
+ ],
1104
+ )
1105
+ def test_accepts_any_spelling(self, raw: str):
1106
+ assert _vault_arg(raw) == Web3.to_checksum_address(self.VAULT)
1107
+
1108
+ @pytest.mark.parametrize("raw", ["", "0x1234", "not an address", "0x" + "g" * 40])
1109
+ def test_rejects_non_addresses(self, raw: str):
1110
+ with pytest.raises(ValueError):
1111
+ _vault_arg(raw)
1112
+
1113
+
1114
+ class TestVaultAddressResolvesSavedChain:
1115
+ """Every spelling the tools accept finds the saved vault's chain."""
1116
+
1117
+ @staticmethod
1118
+ def _config(providers: list[int]):
1119
+ from ipor_fusion.cli.config_store import FusionConfig, VaultEntry
1120
+
1121
+ return FusionConfig(
1122
+ providers={str(c): "https://rpc.example.com" for c in providers},
1123
+ vaults=[VaultEntry(address=_SAVED_VAULT, label="Test", chain_id=1)],
1124
+ )
1125
+
1126
+ @pytest.mark.parametrize(
1127
+ "spelling", [f" {_SAVED_VAULT} ", _SAVED_VAULT[2:], _SAVED_VAULT.upper()]
1128
+ )
1129
+ @pytest.mark.parametrize(
1130
+ "tool", [vault_info, vault_validate, vault_role_accounts, vault_oracle_mapping]
1131
+ )
1132
+ def test_saved_chain_wins_over_other_providers(self, tool, spelling: str):
1133
+ seen: list[int] = []
1134
+
1135
+ def stop(_cfg, chain_id, _block):
1136
+ seen.append(chain_id)
1137
+ raise RuntimeError("stop")
1138
+
1139
+ with (
1140
+ patch(
1141
+ "ipor_fusion.mcp.server.load_config",
1142
+ autospec=True,
1143
+ return_value=self._config([1, 8453]),
1144
+ ),
1145
+ patch("ipor_fusion.mcp.server._build_ctx", autospec=True, side_effect=stop),
1146
+ pytest.raises(RuntimeError, match="stop"),
1147
+ ):
1148
+ tool(spelling)
1149
+ assert seen == [1]
1150
+
1151
+ def test_missing_saved_chain_provider_is_reported_not_substituted(self):
1152
+ with (
1153
+ patch(
1154
+ "ipor_fusion.mcp.server.load_config",
1155
+ autospec=True,
1156
+ return_value=self._config([8453]),
1157
+ ),
1158
+ pytest.raises(ValueError, match="No provider for chain 1"),
1159
+ ):
1160
+ vault_info(f" {_SAVED_VAULT[2:]} ")