ipor-fusion 4.1.0.dev56__tar.gz → 4.2.0.dev9__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 (368) hide show
  1. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.claude-plugin/plugin.json +1 -1
  2. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/AGENTS.md +11 -3
  3. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/CHANGELOG.md +126 -0
  4. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/PKG-INFO +6 -2
  5. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/README.md +5 -1
  6. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/pyproject.toml +1 -1
  7. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/skills/ipor-deploy-vault/SKILL.md +14 -0
  8. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/__init__.py +40 -0
  9. ipor_fusion-4.2.0.dev9/src/ipor_fusion/cli/fuse_cmd.py +108 -0
  10. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/main.py +2 -0
  11. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/erc20.py +7 -2
  12. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/plasma_vault.py +4 -1
  13. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/simulation_result.py +2 -1
  14. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/errors.py +2 -1
  15. ipor_fusion-4.2.0.dev9/src/ipor_fusion/fuse_whitelist.py +401 -0
  16. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/guide/invariants.md +12 -0
  17. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/guide/quickstart.md +2 -0
  18. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/mcp/models.py +26 -0
  19. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/mcp/server.py +29 -0
  20. ipor_fusion-4.2.0.dev9/src/ipor_fusion/onchain_text.py +30 -0
  21. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/preflight.py +42 -1
  22. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/oracle_mapping_reader.py +4 -1
  23. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/registry.py +15 -2
  24. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/types.py +1 -0
  25. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/validation.py +100 -8
  26. ipor_fusion-4.2.0.dev9/tests/test_cli_mcp_fuse_whitelist.py +115 -0
  27. ipor_fusion-4.2.0.dev9/tests/test_fuse_whitelist.py +411 -0
  28. ipor_fusion-4.2.0.dev9/tests/test_onchain_text.py +62 -0
  29. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_preflight.py +7 -0
  30. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_public_api.py +42 -0
  31. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_registry.py +39 -0
  32. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_preflight_base.py +16 -2
  33. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_validation.py +9 -0
  34. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/uv.lock +1 -1
  35. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.claude-plugin/marketplace.json +0 -0
  36. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.env.example +0 -0
  37. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.gemini/settings.json +0 -0
  38. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.git-blame-ignore-revs +0 -0
  39. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.github/workflows/cd.yml +0 -0
  40. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.github/workflows/ci.yml +0 -0
  41. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.github/workflows/commit-lint.yml +0 -0
  42. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.github/workflows/notify-slack.yml +0 -0
  43. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.github/workflows/python-build.yml +0 -0
  44. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.github/workflows/python-publish.yml +0 -0
  45. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.github/workflows/release.yml +0 -0
  46. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.github/workflows/report-slack.yml +0 -0
  47. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.gitignore +0 -0
  48. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.mcp.json +0 -0
  49. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.pre-commit-config.yaml +0 -0
  50. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/.python-version +0 -0
  51. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/CLAUDE.md +0 -0
  52. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/CODEOWNERS +0 -0
  53. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/LICENSE +0 -0
  54. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/MIGRATION_4.md +0 -0
  55. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/build.sh +0 -0
  56. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/examples/CONTRIBUTING.md +0 -0
  57. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/examples/README.md +0 -0
  58. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  59. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  60. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  61. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/examples/external_state_margin_leg_base.py +0 -0
  62. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/examples/hypercore_vault_official_deployment_hyperevm.py +0 -0
  63. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/examples/simple_aave_v3_supply_base.py +0 -0
  64. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/pytest.ini +0 -0
  65. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/scripts/commit-check.sh +0 -0
  66. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/scripts/fusion_error_signatures.py +0 -0
  67. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/about.py +0 -0
  68. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cache.py +0 -0
  69. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/chains.py +0 -0
  70. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/__init__.py +0 -0
  71. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/address_cmd.py +0 -0
  72. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  73. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/config_cmd.py +0 -0
  74. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/config_store.py +0 -0
  75. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/market_cmd.py +0 -0
  76. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/options.py +0 -0
  77. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  78. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/preflight_cmd.py +0 -0
  79. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  80. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/vault_health.py +0 -0
  81. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  82. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  83. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  84. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/config/__init__.py +0 -0
  85. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/config/roles.py +0 -0
  86. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/__init__.py +0 -0
  87. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/access.py +0 -0
  88. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/address.py +0 -0
  89. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/context.py +0 -0
  90. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/context_manager.py +0 -0
  91. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/contract.py +0 -0
  92. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/external_state_executor.py +0 -0
  93. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/fee_manager.py +0 -0
  94. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/fuse.py +0 -0
  95. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/fuse_action.py +0 -0
  96. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/fuse_decoding.py +0 -0
  97. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/fusion_factory.py +0 -0
  98. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/logs.py +0 -0
  99. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/multicall.py +0 -0
  100. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/oracle.py +0 -0
  101. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/rewards_manager.py +0 -0
  102. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/simulation.py +0 -0
  103. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  104. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/__init__.py +0 -0
  105. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  106. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  107. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  108. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  109. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  110. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  111. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  112. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  113. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  114. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/contracts.py +0 -0
  115. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/discovery.py +0 -0
  116. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/errors.py +0 -0
  117. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  118. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  119. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  120. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  121. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/lane.py +0 -0
  122. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/logs.py +0 -0
  123. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/messages.py +0 -0
  124. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/simulation.py +0 -0
  125. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  126. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  127. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  128. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  129. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  130. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/crosschain/transport.py +0 -0
  131. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/dependency_graph.py +0 -0
  132. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/entry_cli.py +0 -0
  133. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/entry_mcp.py +0 -0
  134. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/explorer.py +0 -0
  135. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/field_docs.py +0 -0
  136. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/__init__.py +0 -0
  137. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  138. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/async_action.py +0 -0
  139. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/base.py +0 -0
  140. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  141. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/erc4626.py +0 -0
  142. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  143. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/events.py +0 -0
  144. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/external_state.py +0 -0
  145. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
  146. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  147. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  148. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/hypercore.py +0 -0
  149. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
  150. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/hypercore_pre_hooks.py +0 -0
  151. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/merkl.py +0 -0
  152. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/morpho.py +0 -0
  153. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  154. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  155. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fuses/universal.py +0 -0
  156. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/fusion_errors.py +0 -0
  157. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/guide/__init__.py +0 -0
  158. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/guide/architecture.md +0 -0
  159. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/guide/glossary.md +0 -0
  160. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/hypercore/__init__.py +0 -0
  161. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/market_ids.py +0 -0
  162. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/market_info.py +0 -0
  163. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/mcp/__init__.py +0 -0
  164. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/mcp/guide.py +0 -0
  165. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/morpho_api.py +0 -0
  166. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/py.typed +0 -0
  167. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/__init__.py +0 -0
  168. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/aave_v3.py +0 -0
  169. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/aave_v4.py +0 -0
  170. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/compound_v3.py +0 -0
  171. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/euler_v2.py +0 -0
  172. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/hypercore.py +0 -0
  173. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  174. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/lending_health.py +0 -0
  175. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/morpho.py +0 -0
  176. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  177. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
  178. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/position_manager.py +0 -0
  179. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  180. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  181. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/readers/unpriceable.py +0 -0
  182. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/substrates.py +0 -0
  183. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/vault_data.py +0 -0
  184. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/vault_erc20.py +0 -0
  185. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/vault_info.py +0 -0
  186. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/vault_managers.py +0 -0
  187. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/vault_positions.py +0 -0
  188. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/src/ipor_fusion/vault_reads.py +0 -0
  189. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/UniswapV3UniversalRouter.py +0 -0
  190. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_addresses.py +0 -0
  191. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_crosschain.py +0 -0
  192. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_crosschain_lifecycle.py +0 -0
  193. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_crosschain_recovery.py +0 -0
  194. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_euler_v2.py +0 -0
  195. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_event_args.py +0 -0
  196. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_fake_rpc.py +0 -0
  197. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_foundry.py +0 -0
  198. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_golden.py +0 -0
  199. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_guide.py +0 -0
  200. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_hypercore_model.py +0 -0
  201. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_hypercore_shadow.py +0 -0
  202. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_live.py +0 -0
  203. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_multicall.py +0 -0
  204. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_oracle_mapping_fake.py +0 -0
  205. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_simulate.py +0 -0
  206. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/_validation.py +0 -0
  207. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/addresses.py +0 -0
  208. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/conftest.py +0 -0
  209. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/constants.py +0 -0
  210. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  211. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/hypercore_market55.json +0 -0
  212. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/hypercore_official.json +0 -0
  213. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
  214. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
  215. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
  216. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
  217. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
  218. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
  219. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
  220. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
  221. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_blue.json +0 -0
  222. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
  223. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
  224. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
  225. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
  226. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
  227. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
  228. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
  229. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/simulate_v1_request.json +0 -0
  230. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/clean.json +0 -0
  231. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
  232. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  233. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
  234. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
  235. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
  236. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
  237. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/fetched.json +0 -0
  238. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
  239. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/full.json +0 -0
  240. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
  241. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/full.txt +0 -0
  242. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/rich.json +0 -0
  243. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
  244. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  245. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_about.py +0 -0
  246. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_access_manager.py +0 -0
  247. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_addresses_helper.py +0 -0
  248. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cache.py +0 -0
  249. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_ccip_read_disabled.py +0 -0
  250. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_chains.py +0 -0
  251. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_address.py +0 -0
  252. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_changelog.py +0 -0
  253. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_commands.py +0 -0
  254. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_config_store.py +0 -0
  255. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_helpers.py +0 -0
  256. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_hypercore.py +0 -0
  257. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_lending_health.py +0 -0
  258. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_market_golden.py +0 -0
  259. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_market_morpho_blue.py +0 -0
  260. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_mcp_parity.py +0 -0
  261. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_oracle_mapping.py +0 -0
  262. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_oracle_mapping_golden.py +0 -0
  263. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_pending_requests_scan.py +0 -0
  264. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_preflight.py +0 -0
  265. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_role_accounts.py +0 -0
  266. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_vault_info_golden.py +0 -0
  267. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_vault_predates_getters.py +0 -0
  268. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_cli_vault_validate.py +0 -0
  269. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_contract_call.py +0 -0
  270. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_contract_encoder.py +0 -0
  271. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_ccip_events.py +0 -0
  272. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_ccip_indexer.py +0 -0
  273. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_ccip_quote.py +0 -0
  274. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_chainlink.py +0 -0
  275. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_contracts.py +0 -0
  276. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_encoding.py +0 -0
  277. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_errors.py +0 -0
  278. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_lane.py +0 -0
  279. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_layering.py +0 -0
  280. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_crosschain_transport.py +0 -0
  281. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_docs_typing.py +0 -0
  282. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_erc20.py +0 -0
  283. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_error_hierarchy.py +0 -0
  284. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_examples_crosschain.py +0 -0
  285. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  286. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_examples_hypercore_hyperevm.py +0 -0
  287. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_examples_vaults.py +0 -0
  288. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_explorer.py +0 -0
  289. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_external_state_events.py +0 -0
  290. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_external_state_executor.py +0 -0
  291. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_fee_manager.py +0 -0
  292. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_fuse_decoding.py +0 -0
  293. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_fuse_encoding.py +0 -0
  294. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_fusion_errors.py +0 -0
  295. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_fusion_instance.py +0 -0
  296. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_governance_wrappers.py +0 -0
  297. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_guide.py +0 -0
  298. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_hypercore_deployment.py +0 -0
  299. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_hypercore_events.py +0 -0
  300. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_hypercore_flow.py +0 -0
  301. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_hypercore_live.py +0 -0
  302. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_hypercore_outcome.py +0 -0
  303. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_hypercore_pre_hooks.py +0 -0
  304. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_hypercore_readers.py +0 -0
  305. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_hypercore_simulation.py +0 -0
  306. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_logs.py +0 -0
  307. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_mcp_address.py +0 -0
  308. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_mcp_hypercore.py +0 -0
  309. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_mcp_models.py +0 -0
  310. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_mcp_preflight.py +0 -0
  311. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_mcp_server.py +0 -0
  312. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_mcp_vault_validate.py +0 -0
  313. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_multicall.py +0 -0
  314. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_oracle.py +0 -0
  315. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_oracle_mapping.py +0 -0
  316. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_plasma_vault.py +0 -0
  317. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_public_type_reachability.py +0 -0
  318. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_reader_encoding.py +0 -0
  319. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_revert_decoding.py +0 -0
  320. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_rewards_manager.py +0 -0
  321. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_roles.py +0 -0
  322. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_sdk_layering.py +0 -0
  323. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  324. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  325. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  326. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  327. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  328. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  329. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  330. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  331. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  332. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_examples_arbitrum.py +0 -0
  333. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_examples_base.py +0 -0
  334. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_examples_crosschain.py +0 -0
  335. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_examples_hyperevm.py +0 -0
  336. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_external_state_executor_base.py +0 -0
  337. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  338. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  339. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  340. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_morpho_blue.py +0 -0
  341. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_pilot_v3.py +0 -0
  342. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  343. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  344. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  345. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  346. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_readers_integration.py +0 -0
  347. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_release_funds.py +0 -0
  348. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_swap_on_base.py +0 -0
  349. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_timelock_base.py +0 -0
  350. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  351. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulation_errors.py +0 -0
  352. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_simulation_observation.py +0 -0
  353. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_solidity_compiler.py +0 -0
  354. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_solidity_mirrors.py +0 -0
  355. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_substrates.py +0 -0
  356. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_types_and_events.py +0 -0
  357. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_unpriceable_tokens.py +0 -0
  358. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_vault_data_block.py +0 -0
  359. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_vault_dep_graph.py +0 -0
  360. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_vault_info_fetched_golden.py +0 -0
  361. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_vault_info_onchain_base.py +0 -0
  362. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  363. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_vault_reconciliation_onchain_base.py +0 -0
  364. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_vault_simulator_blocks.py +0 -0
  365. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_web3_context.py +0 -0
  366. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/test_withdraw_manager.py +0 -0
  367. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/typed_client/consumer.py +0 -0
  368. {ipor_fusion-4.1.0.dev56 → ipor_fusion-4.2.0.dev9}/tests/typed_client/rejected.py +0 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ipor-fusion",
3
- "version": "4.0.0",
3
+ "version": "4.1.0",
4
4
  "description": "Skills for building on IPOR Fusion vaults with the ipor-fusion Python SDK, plus the hosted read-only inspection server",
5
5
  "author": {
6
6
  "name": "IPOR Labs",
@@ -174,7 +174,7 @@ checkout's default profile), the pending reader included.
174
174
  subpackages do not list them). Their exceptions stay in `errors` and the top
175
175
  level. `ipor_fusion.guide` keeps its own namespace. The
176
176
  public modules (`about`, `cache`, `chains`, `dependency_graph`, `errors`, `explorer`,
177
- `field_docs`, `market_ids`, `market_info`, `morpho_api`, `preflight`, `registry`, `substrates`, `types`,
177
+ `field_docs`, `fuse_whitelist`, `market_ids`, `market_info`, `morpho_api`, `preflight`, `registry`, `substrates`, `types`,
178
178
  `validation`, `vault_data`, `vault_info`) stay importable for the names they
179
179
  define and the moved names README lists; `cli`, `mcp`, every other module and
180
180
  every submodule of a public subpackage (`core.contract`, `fuses.base`, ...) are
@@ -246,6 +246,13 @@ checkout's default profile), the pending reader included.
246
246
  `registry.py` the ipor-abi address registry (`fetch_address_registry` →
247
247
  `AddressRegistry`, one raw-GitHub file per chain in `REGISTRY_CHAIN_IDS`, cached ten
248
248
  minutes in the process, for good at a commit ref) and the `fusion address` documents;
249
+ `fuse_whitelist.py` the on-chain Fuse Whitelist (`IporFusionFuseWhitelistProxy`,
250
+ resolved through `registry.py`): `read_market_fuses` / `read_fuse_entries` in
251
+ Multicall3 batches, `check_fuses` + `fuse_whitelist_issues` (the warnings
252
+ `validate_vault` and `preflight_execute` add, each naming the active
253
+ replacement) and the `fusion fuse whitelist` document; `getFusesByMarketId`
254
+ returns deprecated fuses too, so state is always read alongside; it reads the
255
+ registry with a 5 s timeout and `stale_if_error`, since the check is optional;
249
256
  `morpho_api.py` the Morpho public GraphQL API client (`fetch_market`, `fetch_vault`,
250
257
  `PUBLIC_ALLOCATOR_ADDRESSES`; it narrows the GraphQL body from `object`);
251
258
  `market_info.py` — `build_morpho_blue_market_json`, `build_meta_morpho_json`, the
@@ -477,7 +484,8 @@ byte, e.g. Ebisu ZAPPER/REGISTRY).
477
484
  ## CLI and MCP
478
485
 
479
486
  `fusion address` (lookup, names, list; the ipor-abi registry through `registry.py`),
480
- `fusion config` (set-provider, set-etherscan-key, show), `fusion market`
487
+ `fusion config` (set-provider, set-etherscan-key, show), `fusion fuse`
488
+ (whitelist; the on-chain Fuse Whitelist through `fuse_whitelist.py`), `fusion market`
481
489
  (morpho-blue, meta-morpho), `fusion vault` (add, remove, list, info, validate,
482
490
  role-accounts, oracle-mapping, preflight). `vault info` runs independent fetch pipelines
483
491
  (vault/asset, fees, WithdrawManager, markets, roles) concurrently on a
@@ -495,7 +503,7 @@ Every CLI command has an MCP tool (`fusion changelog` maps to `server_info`;
495
503
  the rest share names). Read-only: `vault_info`, `vault_validate`, `vault_preflight`,
496
504
  `vault_list`, `vault_role_accounts`, `vault_oracle_mapping`, `market_morpho_blue`,
497
505
  `market_meta_morpho`, `address_lookup`, `address_names`, `address_list`,
498
- `config_show`, `server_info`. Mutating: `vault_add`,
506
+ `fuse_whitelist`, `config_show`, `server_info`. Mutating: `vault_add`,
499
507
  `vault_remove`, `config_set_provider`, `config_set_etherscan_key`. Every new
500
508
  CLI command gets a matching MCP tool with the same argument names; an optional
501
509
  chain or block is `None` when omitted (`ChainArg`, `BlockArg`); a chain of
@@ -2,6 +2,132 @@
2
2
 
3
3
  <!-- version list -->
4
4
 
5
+ ## v4.1.0 (2026-11-03)
6
+
7
+ ### Bug Fixes
8
+
9
+ - **cli**: Accept a 0X prefix in address arguments
10
+ ([`cc23ff7`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/cc23ff7be50ca760eb6adc1a245746bc93a62553))
11
+
12
+ - **cli**: Check address arguments with parse_checksum_address
13
+ ([`4023d07`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/4023d0789ed78d1ab76ce8f44d76a98b65c366f6))
14
+
15
+ - **cli**: Print a set-provider hint that runs as shown
16
+ ([`6dd2894`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/6dd2894693038bae57b256293a4128160f35fc02))
17
+
18
+ - **cli**: Read --block-number 0 as the latest block
19
+ ([`8dd339f`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/8dd339f0d8412389c6a473a57f119e79473e9ef6))
20
+
21
+ - **mcp**: Name the preflight sender in its parse errors
22
+ ([`b1a6115`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/b1a61158a1f25eb9516f0e96d1a5c794ff943c65))
23
+
24
+ - **mcp**: Read block_number=0 as the latest block
25
+ ([`320bb93`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/320bb935726d83fd7787cab9bb82430681ee6a11))
26
+
27
+ - **mcp**: Reject a wrong EIP-55 checksum in the MetaMorpho vault
28
+ ([`02a5159`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/02a5159d727f768a40e97aad6869ff3b0356c418))
29
+
30
+ - **mcp**: Reject a wrong EIP-55 checksum in the preflight sender
31
+ ([`4d5af23`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/4d5af236721c2cd3e9e8a0f52ed045b06039b4fa))
32
+
33
+ - **mcp**: Reject a wrong EIP-55 checksum in vault arguments
34
+ ([`37625ec`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/37625ecb172a3478fc7fb5e522027c71c0a98dcf))
35
+
36
+ - **sdk**: Check EIP-55 in every FusionInstance address field
37
+ ([`951f49a`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/951f49a4ccceecef4a06b8c600c12564da0c6ce5))
38
+
39
+ - **sdk**: Do not follow CCIP-Read lookups from contracts
40
+ ([`51c8ef2`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/51c8ef25e19b9e33c8ea4317a9e1df26ad87dccd))
41
+
42
+ - **sdk**: Read the latest block's number and timestamp in one call
43
+ ([`60a4a8f`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/60a4a8f545714f1013a2f30145837b2d8ad421cb))
44
+
45
+ - **sdk**: Reject a 0X-prefixed zero address
46
+ ([`556ee32`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/556ee329d7954ac39f2b0dff607fa2aba7ba3bdd))
47
+
48
+ - **sdk**: Reject a wrong EIP-55 checksum in the address parsers
49
+ ([`deac726`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/deac7262bb5ccfdc0932eab8d22ed02bd66d4c3b))
50
+
51
+ - **sdk**: Report Euler V2 lending health and never drop a borrow market
52
+ ([`1de4598`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/1de4598248b2a73d322d68359baaa74421244b2e))
53
+
54
+ - **sdk**: Stop reporting a rounding gap as a stale ERC20 cache
55
+ ([`29ffb53`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/29ffb53377cd91308815a0d3ede18acfe640ee4a))
56
+
57
+ - **sdk**: Stop the oracle mapping at a price oracle manager delegation cycle
58
+ ([`1470d93`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/1470d93f85f477e24a85e6a28013f4456149d128))
59
+
60
+ ### Build System
61
+
62
+ - Bump aiohttp, multidict and mcp in the lock
63
+ ([`3c266b1`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/3c266b195f3b6ae4b72bdf8e7ae5a2c165838cc1))
64
+
65
+ ### Documentation
66
+
67
+ - Block 0 reads the latest block in the tools and the CLI
68
+ ([`308ccd2`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/308ccd22cff554c3f31f1414a8e825fac8b00625))
69
+
70
+ - Keep the CCIP example's command gas inside HyperEVM's small block
71
+ ([`5e3a093`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/5e3a093b66c79c9565f89b7c91615cb95c2e1ff7))
72
+
73
+ - **examples**: Build address literals with parse_checksum_address
74
+ ([`c449d13`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/c449d13ab481ec9b13497bb435569d9651f5b38c))
75
+
76
+ - **sdk**: Say the HyperCore pre-hooks take no pre-hook substrates
77
+ ([`b609593`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/b609593ebb4b05bfd2b866e6139f02321323f6a3))
78
+
79
+ - **sdk**: Wire the HyperCore example's pre-hooks with the helper
80
+ ([`edd2776`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/edd277677da59872f5074d8dcba2b6b5cad2daa2))
81
+
82
+ ### Features
83
+
84
+ - **sdk**: Add parse_checksum_address
85
+ ([`a9a6b84`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/a9a6b848e606318fc76fa82dc2c54c7d5b4a94d9))
86
+
87
+ - **sdk**: Expose the HyperCore order and price scales
88
+ ([`b75c645`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/b75c645f95c525114e181519fe75c2348b7962b7))
89
+
90
+ - **sdk**: HyperCore pre-hook wiring
91
+ ([`6f16ae6`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/6f16ae6cbe2d0f3298308f4592538cb06e52eab6))
92
+
93
+ - **sdk**: Read the HyperCore best bid and ask
94
+ ([`5fda9ee`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/5fda9ee754eb8085df3f8c432ce65565c045bddf))
95
+
96
+ - **sdk**: Report the feeds behind a Morpho oracle in the oracle mapping
97
+ ([`c692d72`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/c692d72449805ee98ae786f14d41d28e6de2c24e))
98
+
99
+ - **sdk**: Support TAC (239) in the vault tooling again
100
+ ([`0cc00c3`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/0cc00c3e8d30f5937296ec6dc40896a4e1c766f7))
101
+
102
+ ### Refactoring
103
+
104
+ - **mcp**: Share _vault_arg's input normalization
105
+ ([`80744af`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/80744afd6d52d33ba7e8a075478083aef4048384))
106
+
107
+ - **sdk**: Decode Euler V2 and Dolomite substrates into typed values
108
+ ([`8f4f1ad`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/8f4f1ad5045772da897a3e31d8514b32c6386610))
109
+
110
+ - **sdk**: Make HyperCorePreHookWiring.selectors a class constant
111
+ ([`ae9bf3e`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/ae9bf3e72f31fe795ef5683cd7287b40a1c83d14))
112
+
113
+ - **sdk**: Move the HyperCore pre-hook wiring to its own module
114
+ ([`b150389`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/b1503891468fe4f54379d8ba49ce68d6b3c7e041))
115
+
116
+ - **sdk**: Name the 0x813 precompile POSITION2_PRECOMPILE
117
+ ([`9529f22`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/9529f22e8a1517ef096fe1b4bff56dcaa8139e5a))
118
+
119
+ - **sdk**: Stop coercing HyperCorePreHookWiring's hooks
120
+ ([`759448d`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/759448d02b3d690a5de636ee91363263e7dd0e40))
121
+
122
+ ### Testing
123
+
124
+ - Share a miscased-address helper
125
+ ([`5f769ac`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/5f769ac98160baa0fe2099b3255b0f91d2b4b223))
126
+
127
+ - **sdk**: Probe the core modules' CLI isolation in one subprocess
128
+ ([`3fc160a`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/3fc160a5766171dc7bb471968d2740521b59d69e))
129
+
130
+
5
131
  ## v4.0.0 (2026-10-23)
6
132
 
7
133
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.1.0.dev56
3
+ Version: 4.2.0.dev9
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
@@ -251,6 +251,9 @@ fusion market meta-morpho 0xVAULT_ADDRESS --chain ethereum
251
251
  # Find IPOR Fusion contracts in the ipor-abi registry
252
252
  fusion address lookup SupplyFuseAaveV3 --chain base
253
253
  fusion address list --chain base
254
+
255
+ # Whitelisted fuses of a market: reuse one instead of deploying a copy
256
+ fusion fuse whitelist --chain arbitrum --market-id 11
254
257
  ```
255
258
 
256
259
  ## MCP Server
@@ -309,7 +312,7 @@ Available tools:
309
312
  | `config_set_provider` | Set RPC provider URL for a chain (auto-detects chain ID) |
310
313
  | `config_set_etherscan_key` | Set Etherscan API key (enables contract name resolution) |
311
314
  | `vault_info` | Full on-chain vault state — assets, fuses, balances, fees, lending health, reconciliation |
312
- | `vault_validate` | Health verdict (ok / warning / critical) with the reconciliation, lending-health and ERC20 numbers behind it |
315
+ | `vault_validate` | Health verdict (ok / warning / critical) with the reconciliation, lending-health and ERC20 numbers behind it, plus a warning for each fuse not active in the Fuse Whitelist |
313
316
  | `vault_preflight` | Check execute calldata as its sender would send it: permission, fuses, balance fuses, simulation |
314
317
  | `vault_role_accounts` | Accounts holding each AccessManager role on a vault |
315
318
  | `vault_oracle_mapping` | Price-oracle sources per asset for a vault |
@@ -321,6 +324,7 @@ Available tools:
321
324
  | `address_lookup` | IPOR Fusion contracts by name substring or address (ipor-abi registry) |
322
325
  | `address_names` | Contract names in the registry, with the chains that have them |
323
326
  | `address_list` | One chain's full `{name: address}` registry |
327
+ | `fuse_whitelist` | The fuses the chain's Fuse Whitelist lists for a market (active first) |
324
328
 
325
329
  Configure providers and vaults via `fusion config` or the MCP config tools first.
326
330
 
@@ -202,6 +202,9 @@ fusion market meta-morpho 0xVAULT_ADDRESS --chain ethereum
202
202
  # Find IPOR Fusion contracts in the ipor-abi registry
203
203
  fusion address lookup SupplyFuseAaveV3 --chain base
204
204
  fusion address list --chain base
205
+
206
+ # Whitelisted fuses of a market: reuse one instead of deploying a copy
207
+ fusion fuse whitelist --chain arbitrum --market-id 11
205
208
  ```
206
209
 
207
210
  ## MCP Server
@@ -260,7 +263,7 @@ Available tools:
260
263
  | `config_set_provider` | Set RPC provider URL for a chain (auto-detects chain ID) |
261
264
  | `config_set_etherscan_key` | Set Etherscan API key (enables contract name resolution) |
262
265
  | `vault_info` | Full on-chain vault state — assets, fuses, balances, fees, lending health, reconciliation |
263
- | `vault_validate` | Health verdict (ok / warning / critical) with the reconciliation, lending-health and ERC20 numbers behind it |
266
+ | `vault_validate` | Health verdict (ok / warning / critical) with the reconciliation, lending-health and ERC20 numbers behind it, plus a warning for each fuse not active in the Fuse Whitelist |
264
267
  | `vault_preflight` | Check execute calldata as its sender would send it: permission, fuses, balance fuses, simulation |
265
268
  | `vault_role_accounts` | Accounts holding each AccessManager role on a vault |
266
269
  | `vault_oracle_mapping` | Price-oracle sources per asset for a vault |
@@ -272,6 +275,7 @@ Available tools:
272
275
  | `address_lookup` | IPOR Fusion contracts by name substring or address (ipor-abi registry) |
273
276
  | `address_names` | Contract names in the registry, with the chains that have them |
274
277
  | `address_list` | One chain's full `{name: address}` registry |
278
+ | `fuse_whitelist` | The fuses the chain's Fuse Whitelist lists for a market (active first) |
275
279
 
276
280
  Configure providers and vaults via `fusion config` or the MCP config tools first.
277
281
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.1.0.dev56"
3
+ version = "4.2.0.dev9"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -68,6 +68,18 @@ greppable.
68
68
  `AaveV3WithPriceOracleMiddlewareBalanceFuse`, Arbitrum only the latter, so a
69
69
  name that resolves on one chain may not exist on the next. Resolve
70
70
  `(chain, name)` in `ipor-abi`; never reuse an address across chains.
71
+ A registry entry is not a whitelist entry. Before adding or deploying a
72
+ fuse, check the chain's Fuse Whitelist: `fusion fuse whitelist --chain base
73
+ --market-id 11` or the MCP tool `fuse_whitelist` lists a market's active
74
+ fuses. On-chain it is `IporFusionFuseWhitelistProxy` in the same
75
+ `addresses.json`: `getFusesByMarketId(market_id)` returns a market's fuses,
76
+ active and deprecated together, and only those whose
77
+ `getFuseByAddress(fuse)` reports `fuseState` 1 (active) belong in a new
78
+ vault. Use an active fuse when one covers the action. A redeployed or
79
+ forked copy of a whitelisted fuse is never whitelisted, and the IPOR app
80
+ shows its market as unknown; a fuse for an action no active fuse covers
81
+ goes through the whitelist review at
82
+ https://ipor.io/docs/build-on-fusion/integrating-a-new-market.md.
71
83
  6. **`.send(ctx)` signs locally and needs a private key in the `Web3Context`;
72
84
  `.call(ctx)` previews without one.** Sending through a context built with
73
85
  `signer=` alone raises `ValueError("Private key required for sending
@@ -238,6 +250,8 @@ Resolve fuse addresses by registry name and chain from `ipor-abi`
238
250
  `fusion address lookup SupplyFuseAaveV3 --chain base`, or the MCP tool
239
251
  `address_lookup` (the hosted server's `fusion_address_lookup`). The SDK class
240
252
  for a registry name swaps the parts: `SupplyFuseAaveV3` is `AaveV3SupplyFuse`.
253
+ Then confirm the fuse is active in the chain's Fuse Whitelist with
254
+ `fusion fuse whitelist` or the MCP tool `fuse_whitelist` (invariant 5).
241
255
 
242
256
  ## Pointers
243
257
 
@@ -146,6 +146,26 @@ from ipor_fusion.errors import (
146
146
  )
147
147
  from ipor_fusion.explorer import get_contract_name, get_deployment_tx
148
148
  from ipor_fusion.field_docs import DOCS
149
+ from ipor_fusion.fuse_whitelist import (
150
+ FUSE_WHITELIST_READ_ERRORS,
151
+ FUSE_WHITELIST_REGISTRY_NAME,
152
+ FuseIssueKind,
153
+ FuseRole,
154
+ FuseState,
155
+ FuseWhitelist,
156
+ FuseWhitelistCheck,
157
+ FuseWhitelistIssue,
158
+ FuseWhitelistJson,
159
+ WhitelistEntry,
160
+ WhitelistEntryJson,
161
+ build_fuse_whitelist_json,
162
+ check_fuses,
163
+ fetch_fuse_whitelist_json,
164
+ fuse_whitelist_for_chain,
165
+ fuse_whitelist_issues,
166
+ read_fuse_entries,
167
+ read_market_fuses,
168
+ )
149
169
  from ipor_fusion.fuses import (
150
170
  AaveV3BorrowFuse,
151
171
  AaveV3SupplyFuse,
@@ -405,6 +425,7 @@ from ipor_fusion.validation import (
405
425
  VaultState,
406
426
  VaultValidation,
407
427
  WithdrawQueue,
428
+ read_vault_fuse_whitelist,
408
429
  validate_vault,
409
430
  validate_vault_state,
410
431
  )
@@ -537,6 +558,24 @@ __all__ = [
537
558
  "fetch_address_registries",
538
559
  "fetch_address_registry",
539
560
  "registry_url",
561
+ "FUSE_WHITELIST_READ_ERRORS",
562
+ "FUSE_WHITELIST_REGISTRY_NAME",
563
+ "FuseIssueKind",
564
+ "FuseRole",
565
+ "FuseState",
566
+ "FuseWhitelist",
567
+ "FuseWhitelistCheck",
568
+ "FuseWhitelistIssue",
569
+ "FuseWhitelistJson",
570
+ "WhitelistEntry",
571
+ "WhitelistEntryJson",
572
+ "build_fuse_whitelist_json",
573
+ "check_fuses",
574
+ "fetch_fuse_whitelist_json",
575
+ "fuse_whitelist_for_chain",
576
+ "fuse_whitelist_issues",
577
+ "read_fuse_entries",
578
+ "read_market_fuses",
540
579
  "ContextManager",
541
580
  "Call",
542
581
  "get_logs_adaptive",
@@ -791,6 +830,7 @@ __all__ = [
791
830
  "WithdrawQueue",
792
831
  "validate_vault",
793
832
  "validate_vault_state",
833
+ "read_vault_fuse_whitelist",
794
834
  "compute_update_groups",
795
835
  "compute_update_reach",
796
836
  "find_markets_missing_erc20_dependency",
@@ -0,0 +1,108 @@
1
+ """`fusion fuse whitelist` — the fuses the chain's Fuse Whitelist lists for a market."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json as json_lib
6
+ from datetime import UTC, datetime
7
+
8
+ import click
9
+
10
+ from ipor_fusion.cli.config_store import load_config
11
+ from ipor_fusion.cli.options import BLOCK_NUMBER, CHAIN, _resolve_provider
12
+ from ipor_fusion.cli.vault_rendering import _print_table
13
+ from ipor_fusion.core.context import Web3Context
14
+ from ipor_fusion.errors import (
15
+ AddressNotInRegistryError,
16
+ AddressRegistryError,
17
+ EmptyCallResultError,
18
+ UnsupportedChainError,
19
+ )
20
+ from ipor_fusion.fuse_whitelist import MAX_MARKET_ID, fetch_fuse_whitelist_json
21
+ from ipor_fusion.types import ChainId, MarketId
22
+
23
+
24
+ @click.group()
25
+ def fuse() -> None:
26
+ """Inspect fuses: which ones IPOR whitelists for a market."""
27
+
28
+
29
+ @fuse.command("whitelist")
30
+ @click.option(
31
+ "--chain",
32
+ "chain_id",
33
+ type=CHAIN,
34
+ required=True,
35
+ help="Chain ID or name (ethereum, base, arbitrum, ...).",
36
+ )
37
+ @click.option(
38
+ "--market-id",
39
+ "market_id",
40
+ type=click.IntRange(min=0, max=MAX_MARKET_ID),
41
+ required=True,
42
+ help="Numeric market ID (IporFusionMarkets), e.g. 11 for EULER_V2.",
43
+ )
44
+ @click.option(
45
+ "--block-number",
46
+ "--block",
47
+ "block_number",
48
+ type=BLOCK_NUMBER,
49
+ default=None,
50
+ help="Block number for on-chain reads (0 or omitted: latest).",
51
+ )
52
+ @click.option(
53
+ "--include-deprecated",
54
+ is_flag=True,
55
+ default=False,
56
+ help="Also list deprecated and removed fuses.",
57
+ )
58
+ @click.option(
59
+ "--json",
60
+ "json_output",
61
+ is_flag=True,
62
+ default=False,
63
+ help="Emit machine-readable JSON instead of a table.",
64
+ )
65
+ def whitelist(
66
+ chain_id: ChainId,
67
+ market_id: int,
68
+ block_number: int | None,
69
+ include_deprecated: bool,
70
+ json_output: bool,
71
+ ) -> None:
72
+ """List the whitelisted fuses of a market: use one of these instead of
73
+ deploying a copy, which the IPOR app would show as unknown."""
74
+ ctx = Web3Context.from_url(_resolve_provider(load_config(), chain_id))
75
+ if block_number is not None:
76
+ ctx = ctx.at_block(block_number)
77
+ try:
78
+ document = fetch_fuse_whitelist_json(
79
+ ctx, MarketId(market_id), include_deprecated=include_deprecated
80
+ )
81
+ except (
82
+ AddressNotInRegistryError,
83
+ AddressRegistryError,
84
+ EmptyCallResultError,
85
+ UnsupportedChainError,
86
+ ) as exc:
87
+ raise click.UsageError(str(exc)) from exc
88
+ if json_output:
89
+ click.echo(json_lib.dumps(document, indent=2))
90
+ return
91
+ click.secho(
92
+ f"Fuse Whitelist {document['whitelist']} on {document['chain']},"
93
+ f" market {document['market']}",
94
+ bold=True,
95
+ )
96
+ _print_table(
97
+ ("Fuse", "State", "Type", "Role", "Added"),
98
+ [
99
+ (
100
+ f["fuse"],
101
+ f["state"],
102
+ f["type_name"],
103
+ f["role"] or "?",
104
+ datetime.fromtimestamp(f["added_at"], UTC).date().isoformat(),
105
+ )
106
+ for f in document["fuses"]
107
+ ],
108
+ )
@@ -8,6 +8,7 @@ import click
8
8
  from ipor_fusion.cli.address_cmd import address
9
9
  from ipor_fusion.cli.changelog_cmd import changelog
10
10
  from ipor_fusion.cli.config_cmd import config
11
+ from ipor_fusion.cli.fuse_cmd import fuse
11
12
  from ipor_fusion.cli.market_cmd import market
12
13
  from ipor_fusion.cli.preflight_cmd import preflight
13
14
  from ipor_fusion.cli.vault_cmd import vault
@@ -34,6 +35,7 @@ def cli(ctx: click.Context, verbose: bool, quiet: bool, no_color: bool) -> None:
34
35
  cli.add_command(address)
35
36
  cli.add_command(changelog)
36
37
  cli.add_command(config)
38
+ cli.add_command(fuse)
37
39
  cli.add_command(market)
38
40
  cli.add_command(vault)
39
41
  vault.add_command(preflight)
@@ -1,6 +1,7 @@
1
1
  from eth_typing import ChecksumAddress
2
2
 
3
3
  from ipor_fusion.core.contract import Call, ContractWrapper
4
+ from ipor_fusion.onchain_text import sanitize_onchain_text
4
5
  from ipor_fusion.types import Amount, Decimals
5
6
 
6
7
 
@@ -26,10 +27,14 @@ class ERC20(ContractWrapper):
26
27
  return self._view("decimals()", output_types=["uint256"], decoder=Decimals)
27
28
 
28
29
  def symbol(self) -> Call[str]:
29
- return self._view("symbol()", output_types=["string"])
30
+ return self._view(
31
+ "symbol()", output_types=["string"], decoder=sanitize_onchain_text
32
+ )
30
33
 
31
34
  def name(self) -> Call[str]:
32
- return self._view("name()", output_types=["string"])
35
+ return self._view(
36
+ "name()", output_types=["string"], decoder=sanitize_onchain_text
37
+ )
33
38
 
34
39
  def total_supply(self) -> Call[Amount]:
35
40
  return self._view("totalSupply()", output_types=["uint256"], decoder=Amount)
@@ -18,6 +18,7 @@ from ipor_fusion.core.context import Web3Context
18
18
  from ipor_fusion.core.contract import Call, ContractWrapper
19
19
  from ipor_fusion.core.fuse_action import FuseAction
20
20
  from ipor_fusion.errors import EmptyCallResultError, UnsupportedVaultVersionError
21
+ from ipor_fusion.onchain_text import sanitize_onchain_text
21
22
  from ipor_fusion.types import (
22
23
  ZERO_ADDRESS,
23
24
  AccessManagerAddress,
@@ -614,7 +615,9 @@ class PlasmaVault(ContractWrapper):
614
615
  return self._view("totalSupply()", output_types=["uint256"], decoder=Shares)
615
616
 
616
617
  def name(self) -> Call[str]:
617
- return self._view("name()", output_types=["string"])
618
+ return self._view(
619
+ "name()", output_types=["string"], decoder=sanitize_onchain_text
620
+ )
618
621
 
619
622
  def underlying_asset_address(self) -> Call[ChecksumAddress]:
620
623
  return self._view(
@@ -13,6 +13,7 @@ from eth_typing import ChecksumAddress
13
13
  from hexbytes import HexBytes
14
14
 
15
15
  from ipor_fusion.errors import SimulationError, SimulationRunError, decode_custom_error
16
+ from ipor_fusion.onchain_text import sanitize_onchain_text
16
17
 
17
18
 
18
19
  class QueuedCall(Protocol):
@@ -295,7 +296,7 @@ def _decode_revert(return_data: HexBytes, error: str | None) -> str | None:
295
296
  if selector == b"\x08\xc3\x79\xa0": # Error(string)
296
297
  try:
297
298
  (msg,) = decode(["string"], bytes(return_data[4:]))
298
- return msg
299
+ return sanitize_onchain_text(msg)
299
300
  except (DecodingError, OverflowError, ValueError):
300
301
  pass
301
302
  if selector == b"\x4e\x48\x7b\x71": # Panic(uint256)
@@ -11,6 +11,7 @@ from web3 import Web3
11
11
  from web3.types import TxParams, TxReceipt
12
12
 
13
13
  from ipor_fusion.fusion_errors import FUSION_ERROR_SIGNATURES
14
+ from ipor_fusion.onchain_text import sanitize_onchain_text
14
15
  from ipor_fusion.types import TxHash
15
16
 
16
17
  log = logging.getLogger(__name__)
@@ -95,7 +96,7 @@ def _decode_revert_reason(data: bytes) -> str:
95
96
  if selector == ERROR_SELECTOR:
96
97
  try:
97
98
  (reason,) = abi_decode(["string"], payload)
98
- return f'Error("{reason}")'
99
+ return f'Error("{sanitize_onchain_text(reason)}")'
99
100
  except Exception:
100
101
  return f"Error(<decode failed>: 0x{payload.hex()[:64]})"
101
102