ipor-fusion 4.0.0.dev308__tar.gz → 4.0.0.dev315__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 (363) hide show
  1. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/AGENTS.md +15 -52
  2. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/MIGRATION_4.md +49 -0
  3. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/PKG-INFO +13 -24
  4. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/README.md +12 -23
  5. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/examples/README.md +0 -23
  6. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/pyproject.toml +1 -1
  7. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/pytest.ini +0 -1
  8. ipor_fusion-4.0.0.dev315/scripts/fusion_error_signatures.py +137 -0
  9. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/contract.py +13 -1
  10. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/__init__.py +6 -0
  11. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/contracts.py +38 -5
  12. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/events.py +125 -63
  13. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/lane.py +5 -0
  14. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/transport.py +23 -9
  15. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/contracts.py +12 -9
  16. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/errors.py +72 -4
  17. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/fuses/ccip.py +21 -3
  18. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/lane.py +34 -2
  19. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/messages.py +51 -12
  20. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/simulation.py +4 -1
  21. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/stargate/contracts.py +17 -4
  22. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/stargate/lane.py +1 -0
  23. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/transport.py +14 -1
  24. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/errors.py +4 -0
  25. ipor_fusion-4.0.0.dev315/src/ipor_fusion/fusion_errors.py +1437 -0
  26. ipor_fusion-4.0.0.dev315/tests/_crosschain.py +252 -0
  27. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_crosschain_lifecycle.py +20 -115
  28. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_crosschain_recovery.py +7 -3
  29. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/conftest.py +0 -13
  30. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_contract_call.py +15 -0
  31. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_contract_encoder.py +1 -0
  32. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_ccip_events.py +36 -16
  33. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_contracts.py +46 -15
  34. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_encoding.py +69 -15
  35. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_lane.py +53 -8
  36. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_transport.py +13 -0
  37. ipor_fusion-4.0.0.dev315/tests/test_fusion_errors.py +122 -0
  38. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_public_api.py +3 -0
  39. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_claim_merkl_wrapper_base.py +3 -1
  40. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_crosschain_hyperevm.py +86 -428
  41. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_timelock_base.py +1 -1
  42. ipor_fusion-4.0.0.dev308/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -1026
  43. ipor_fusion-4.0.0.dev308/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -707
  44. ipor_fusion-4.0.0.dev308/scripts/crosschain_readiness.py +0 -1129
  45. ipor_fusion-4.0.0.dev308/tests/_crosschain.py +0 -574
  46. ipor_fusion-4.0.0.dev308/tests/test_crosschain_readiness.py +0 -160
  47. ipor_fusion-4.0.0.dev308/tests/test_crosschain_readiness_report.py +0 -821
  48. ipor_fusion-4.0.0.dev308/tests/test_examples_composed_hypercore.py +0 -239
  49. ipor_fusion-4.0.0.dev308/tests/test_examples_crosschain.py +0 -138
  50. ipor_fusion-4.0.0.dev308/tests/test_readiness_selection.py +0 -84
  51. ipor_fusion-4.0.0.dev308/tests/test_simulate_crosschain_canary.py +0 -127
  52. ipor_fusion-4.0.0.dev308/tests/test_simulate_crosschain_hypercore.py +0 -385
  53. ipor_fusion-4.0.0.dev308/tests/test_simulate_crosschain_lifecycle.py +0 -18
  54. ipor_fusion-4.0.0.dev308/tests/test_simulate_examples_crosschain.py +0 -44
  55. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.claude-plugin/marketplace.json +0 -0
  56. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.claude-plugin/plugin.json +0 -0
  57. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.env.example +0 -0
  58. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.gemini/settings.json +0 -0
  59. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.git-blame-ignore-revs +0 -0
  60. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.github/workflows/cd.yml +0 -0
  61. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.github/workflows/ci.yml +0 -0
  62. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.github/workflows/commit-lint.yml +0 -0
  63. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.github/workflows/notify-slack.yml +0 -0
  64. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.github/workflows/python-build.yml +0 -0
  65. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.github/workflows/python-publish.yml +0 -0
  66. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.github/workflows/release.yml +0 -0
  67. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.github/workflows/report-slack.yml +0 -0
  68. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.gitignore +0 -0
  69. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.mcp.json +0 -0
  70. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.pre-commit-config.yaml +0 -0
  71. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/.python-version +0 -0
  72. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/CHANGELOG.md +0 -0
  73. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/CLAUDE.md +0 -0
  74. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/CODEOWNERS +0 -0
  75. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/LICENSE +0 -0
  76. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/build.sh +0 -0
  77. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/examples/CONTRIBUTING.md +0 -0
  78. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  79. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  80. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/examples/external_state_margin_leg_base.py +0 -0
  81. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/examples/simple_aave_v3_supply_base.py +0 -0
  82. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/scripts/commit-check.sh +0 -0
  83. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/skills/ipor-deploy-vault/SKILL.md +0 -0
  84. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/__init__.py +0 -0
  85. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/about.py +0 -0
  86. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cache.py +0 -0
  87. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/chains.py +0 -0
  88. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/__init__.py +0 -0
  89. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/address_cmd.py +0 -0
  90. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  91. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/config_cmd.py +0 -0
  92. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/config_store.py +0 -0
  93. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/main.py +0 -0
  94. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/market_cmd.py +0 -0
  95. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/options.py +0 -0
  96. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  97. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/preflight_cmd.py +0 -0
  98. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  99. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/vault_health.py +0 -0
  100. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  101. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  102. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  103. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/config/__init__.py +0 -0
  104. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/config/roles.py +0 -0
  105. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/__init__.py +0 -0
  106. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/access.py +0 -0
  107. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/address.py +0 -0
  108. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/context.py +0 -0
  109. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/context_manager.py +0 -0
  110. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/erc20.py +0 -0
  111. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/external_state_executor.py +0 -0
  112. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/fee_manager.py +0 -0
  113. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/fuse.py +0 -0
  114. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/fuse_action.py +0 -0
  115. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/fuse_decoding.py +0 -0
  116. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/fusion_factory.py +0 -0
  117. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/logs.py +0 -0
  118. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/multicall.py +0 -0
  119. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/oracle.py +0 -0
  120. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/plasma_vault.py +0 -0
  121. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/rewards_manager.py +0 -0
  122. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/simulation.py +0 -0
  123. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/simulation_result.py +0 -0
  124. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  125. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  126. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  127. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  128. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  129. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  130. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/discovery.py +0 -0
  131. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  132. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  133. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  134. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/logs.py +0 -0
  135. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  136. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  137. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  138. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/dependency_graph.py +0 -0
  139. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/entry_cli.py +0 -0
  140. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/entry_mcp.py +0 -0
  141. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/explorer.py +0 -0
  142. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/field_docs.py +0 -0
  143. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/__init__.py +0 -0
  144. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  145. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/async_action.py +0 -0
  146. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/base.py +0 -0
  147. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  148. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/erc4626.py +0 -0
  149. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  150. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/events.py +0 -0
  151. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/external_state.py +0 -0
  152. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
  153. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  154. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  155. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/hypercore.py +0 -0
  156. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
  157. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/merkl.py +0 -0
  158. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/morpho.py +0 -0
  159. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  160. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  161. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/fuses/universal.py +0 -0
  162. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/guide/__init__.py +0 -0
  163. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/guide/architecture.md +0 -0
  164. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/guide/glossary.md +0 -0
  165. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/guide/invariants.md +0 -0
  166. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/guide/quickstart.md +0 -0
  167. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/hypercore/__init__.py +0 -0
  168. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/market_ids.py +0 -0
  169. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/market_info.py +0 -0
  170. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/mcp/__init__.py +0 -0
  171. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/mcp/guide.py +0 -0
  172. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/mcp/models.py +0 -0
  173. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/mcp/server.py +0 -0
  174. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/morpho_api.py +0 -0
  175. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/preflight.py +0 -0
  176. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/py.typed +0 -0
  177. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/__init__.py +0 -0
  178. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/aave_v3.py +0 -0
  179. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/aave_v4.py +0 -0
  180. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/compound_v3.py +0 -0
  181. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/hypercore.py +0 -0
  182. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  183. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/lending_health.py +0 -0
  184. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/morpho.py +0 -0
  185. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  186. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
  187. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  188. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/position_manager.py +0 -0
  189. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  190. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  191. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/readers/unpriceable.py +0 -0
  192. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/registry.py +0 -0
  193. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/substrates.py +0 -0
  194. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/types.py +0 -0
  195. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/validation.py +0 -0
  196. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/vault_data.py +0 -0
  197. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/vault_erc20.py +0 -0
  198. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/vault_info.py +0 -0
  199. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/vault_managers.py +0 -0
  200. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/vault_positions.py +0 -0
  201. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/src/ipor_fusion/vault_reads.py +0 -0
  202. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/UniswapV3UniversalRouter.py +0 -0
  203. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_euler_v2.py +0 -0
  204. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_event_args.py +0 -0
  205. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_fake_rpc.py +0 -0
  206. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_foundry.py +0 -0
  207. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_golden.py +0 -0
  208. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_guide.py +0 -0
  209. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_hypercore_model.py +0 -0
  210. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_hypercore_shadow.py +0 -0
  211. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_live.py +0 -0
  212. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_multicall.py +0 -0
  213. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_oracle_mapping_fake.py +0 -0
  214. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_simulate.py +0 -0
  215. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/_validation.py +0 -0
  216. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/addresses.py +0 -0
  217. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/constants.py +0 -0
  218. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  219. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/hypercore_market55.json +0 -0
  220. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/hypercore_official.json +0 -0
  221. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
  222. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
  223. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
  224. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
  225. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
  226. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
  227. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
  228. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
  229. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_blue.json +0 -0
  230. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
  231. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
  232. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
  233. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
  234. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
  235. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
  236. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
  237. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/simulate_v1_request.json +0 -0
  238. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/clean.json +0 -0
  239. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
  240. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  241. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
  242. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
  243. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
  244. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
  245. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/fetched.json +0 -0
  246. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
  247. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/full.json +0 -0
  248. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
  249. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/full.txt +0 -0
  250. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/rich.json +0 -0
  251. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
  252. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  253. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_about.py +0 -0
  254. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_access_manager.py +0 -0
  255. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cache.py +0 -0
  256. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_chains.py +0 -0
  257. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_address.py +0 -0
  258. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_changelog.py +0 -0
  259. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_commands.py +0 -0
  260. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_config_store.py +0 -0
  261. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_helpers.py +0 -0
  262. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_hypercore.py +0 -0
  263. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_lending_health.py +0 -0
  264. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_market_golden.py +0 -0
  265. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_market_morpho_blue.py +0 -0
  266. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_mcp_parity.py +0 -0
  267. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_oracle_mapping.py +0 -0
  268. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_oracle_mapping_golden.py +0 -0
  269. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_pending_requests_scan.py +0 -0
  270. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_preflight.py +0 -0
  271. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_role_accounts.py +0 -0
  272. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_vault_info_golden.py +0 -0
  273. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_vault_predates_getters.py +0 -0
  274. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_cli_vault_validate.py +0 -0
  275. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_ccip_indexer.py +0 -0
  276. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_ccip_quote.py +0 -0
  277. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_chainlink.py +0 -0
  278. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_errors.py +0 -0
  279. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_crosschain_layering.py +0 -0
  280. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_docs_typing.py +0 -0
  281. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_erc20.py +0 -0
  282. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_error_hierarchy.py +0 -0
  283. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  284. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_examples_vaults.py +0 -0
  285. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_explorer.py +0 -0
  286. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_external_state_events.py +0 -0
  287. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_external_state_executor.py +0 -0
  288. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_fee_manager.py +0 -0
  289. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_fuse_decoding.py +0 -0
  290. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_fuse_encoding.py +0 -0
  291. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_fusion_instance.py +0 -0
  292. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_governance_wrappers.py +0 -0
  293. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_guide.py +0 -0
  294. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_hypercore_deployment.py +0 -0
  295. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_hypercore_events.py +0 -0
  296. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_hypercore_flow.py +0 -0
  297. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_hypercore_live.py +0 -0
  298. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_hypercore_outcome.py +0 -0
  299. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_hypercore_readers.py +0 -0
  300. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_hypercore_simulation.py +0 -0
  301. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_logs.py +0 -0
  302. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_mcp_address.py +0 -0
  303. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_mcp_hypercore.py +0 -0
  304. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_mcp_models.py +0 -0
  305. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_mcp_preflight.py +0 -0
  306. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_mcp_server.py +0 -0
  307. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_mcp_vault_validate.py +0 -0
  308. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_multicall.py +0 -0
  309. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_oracle.py +0 -0
  310. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_oracle_mapping.py +0 -0
  311. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_plasma_vault.py +0 -0
  312. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_preflight.py +0 -0
  313. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_public_type_reachability.py +0 -0
  314. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_reader_encoding.py +0 -0
  315. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_registry.py +0 -0
  316. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_revert_decoding.py +0 -0
  317. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_rewards_manager.py +0 -0
  318. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_roles.py +0 -0
  319. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_sdk_layering.py +0 -0
  320. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  321. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  322. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  323. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  324. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  325. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  326. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  327. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_examples_arbitrum.py +0 -0
  328. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_examples_base.py +0 -0
  329. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_external_state_executor_base.py +0 -0
  330. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  331. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  332. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  333. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_morpho_blue.py +0 -0
  334. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_pilot_v3.py +0 -0
  335. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  336. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  337. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  338. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  339. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_preflight_base.py +0 -0
  340. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_readers_integration.py +0 -0
  341. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_release_funds.py +0 -0
  342. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_swap_on_base.py +0 -0
  343. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  344. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulation_errors.py +0 -0
  345. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_simulation_observation.py +0 -0
  346. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_solidity_compiler.py +0 -0
  347. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_solidity_mirrors.py +0 -0
  348. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_substrates.py +0 -0
  349. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_types_and_events.py +0 -0
  350. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_unpriceable_tokens.py +0 -0
  351. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_validation.py +0 -0
  352. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_vault_data_block.py +0 -0
  353. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_vault_dep_graph.py +0 -0
  354. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_vault_info_fetched_golden.py +0 -0
  355. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_vault_info_onchain_base.py +0 -0
  356. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  357. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_vault_reconciliation_onchain_base.py +0 -0
  358. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_vault_simulator_blocks.py +0 -0
  359. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_web3_context.py +0 -0
  360. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/test_withdraw_manager.py +0 -0
  361. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/typed_client/consumer.py +0 -0
  362. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/tests/typed_client/rejected.py +0 -0
  363. {ipor_fusion-4.0.0.dev308 → ipor_fusion-4.0.0.dev315}/uv.lock +0 -0
@@ -3,9 +3,7 @@
3
3
  `ipor-fusion` is the Python SDK for IPOR Fusion Plasma Vaults: typed fuse
4
4
  encoders, on-chain readers, and a `fusion` CLI plus `fusion-mcp` MCP server
5
5
  built on the same SDK. Published to PyPI. It is a library and inspection
6
- tooling, not an automation service. `scripts/crosschain_readiness.py` is a
7
- read-only diagnostic run on demand, not a keeper or production monitor; any
8
- scheduled run of it belongs to the monitoring repository.
6
+ tooling, not an automation service.
9
7
 
10
8
  Related repositories (siblings, referenced by name; clone paths vary):
11
9
  - [ipor-fusion](https://github.com/IPOR-Labs/ipor-fusion) — Solidity contracts, the source of truth for market ids, roles and substrates.
@@ -29,8 +27,6 @@ uv run ruff check ./ # lint: bandit S,
29
27
  uv run pyright # types, basic mode, src + tests + examples + scripts
30
28
  uv run pytest # all tests + coverage gate (fail_under = 98, mcp/ included)
31
29
  uv run pytest -m "cli or mcp" --no-cov # CLI/MCP subset (the full suite is mostly offline too)
32
- uv run pytest --run-readiness -m readiness --no-cov -rA # opt-in live Ethereum-hub POC checks
33
- uv run python scripts/crosschain_readiness.py --output /tmp/crosschain-readiness.json # live Arbitrum/HyperEVM report
34
30
  uv run pytest tests/test_fuse_encoding.py -k aave --no-cov # single file / test
35
31
  UPDATE_GOLDEN=1 uv run pytest -k golden --no-cov # rewrite pinned CLI/MCP output (tests/fixtures/*_golden/)
36
32
  uv lock --check # uv.lock in sync with pyproject.toml
@@ -74,14 +70,13 @@ public Solidity sources from GitHub). Skip only for an unavailable source; an
74
70
  exception from the
75
71
  SDK is a test failure, never a skip. Never print `.env` or a provider URL: they
76
72
  embed API keys, so skip and fail messages carry the exception type only.
77
- `HYPEREVM_PROVIDER_URL` is used by the HyperEVM lifecycle/deployment tests and
78
- the readiness script; general PR CI does not supply it.
79
- `test_simulate_crosschain_hyperevm.py` rehearses Arbitrum → HyperEVM on pinned blocks,
80
- parametrized by `generation`: `v2` and `v3` run the live factory pairs (`FactoryPair`:
81
- address, pins, creation-code hashes, route and dispatcher deployment gas limits) with
82
- executors from the creation code they store; `source` builds a factory pair from
83
- `FUSE_SOURCE_REVISION` inside the simulation. All need `IPOR_FUSION_CONTRACTS_DIR` at
84
- that revision (the fuses are compiled from it); a checkout without `node_modules` also
73
+ `HYPEREVM_PROVIDER_URL` is used by the Arbitrum → HyperEVM rehearsal and the
74
+ HyperCore tests; general PR CI does not supply it.
75
+ `test_simulate_crosschain_hyperevm.py` rehearses Arbitrum → HyperEVM on pinned blocks
76
+ with a CCIP factory pair compiled from `FUSE_SOURCE_REVISION` (the contracts release
77
+ the official deployment was built from) and built inside the simulation; the SDK
78
+ supports only that release, so there is no live-pair generation. It needs
79
+ `IPOR_FUSION_CONTRACTS_DIR` at that revision; a checkout without `node_modules` also
85
80
  needs `IPOR_FUSION_FOUNDRY_REMAPPINGS` for OpenZeppelin. `test_crosschain_ccip_events.py`
86
81
  mirrors the CCIP event registry from a checkout at its own `CONTRACTS_REVISION`.
87
82
  `test_solidity_compiler.py` unit-tests that compiler helper (`tests/_foundry.py`)
@@ -89,18 +84,6 @@ offline, with `forge` and `git` mocked. The checkout-based tests above skip when
89
84
  external prerequisites are unavailable. `test_hypercore_live.py`,
90
85
  `test_hypercore_deployment.py` and `test_hypercore_simulation.py` need
91
86
  `HYPEREVM_PROVIDER_URL` as well.
92
- `test_simulate_crosschain_lifecycle.py` drives the mainnet POC deployment from
93
- Ethereum to every spoke on every transport through `CrosschainLane` and
94
- `CrosschainSimulator`; the fixtures (`Chain`, `Deployment`, `Spoke`, pinned
95
- blocks) live in `tests/_crosschain.py`. A planned spoke (HyperEVM) is a
96
- `pending` chain there and an `xfail(strict=True)` param until it is wired.
97
- `test_simulate_crosschain_canary.py` runs the same lifecycle on `CANARY` and
98
- `CANARY_V3`, the live Arbitrum → HyperEVM USDC canaries on the pilot-v2 and v3 CCIP
99
- factory pairs, each pinned right after its last transaction, then checks the final gates and every delivery's receiver
100
- gas against its route limit; a `Chain.simulated_gas_limit` lifts HyperEVM's 3 M
101
- small-block pin to 30 M and `Deployment.ccip_debits_sent_amount` /
102
- `attestation_zero_dust_sd` carry the executor generation's accounting into `Run`.
103
- It needs `ARBITRUM_PROVIDER_URL` and `HYPEREVM_PROVIDER_URL`.
104
87
  HyperCore (market 55) cannot be simulated directly: the HyperEVM RPC ignores code
105
88
  overrides at the precompile addresses `0x800`–`0x813`, and the public Hyperliquid RPC
106
89
  has no `eth_simulateV1`. `tests/_hypercore_shadow.py` therefore compiles the HyperCore
@@ -110,33 +93,8 @@ CoreWriter constants redirected to ordinary addresses, proves the rest is identi
110
93
  the deployed runtimes, and `tests/_hypercore_model.py` answers those addresses through
111
94
  `VaultSimulator.with_state_override_provider`. Core never applies anything there: the
112
95
  tests prove EVM validation under supplied Core state. `test_hypercore_simulation.py`
113
- runs one vault cycle; `test_simulate_crosschain_hypercore.py` runs the composed flow
114
- (v3 canary hub → CCIP → the market-55 vault → a trade → recall → claim) and holds every
115
- CCIP delivery to its route gas limit. Both skip without the source directory;
116
- `test_hypercore_simulation.py` also needs `HYPEREVM_PROVIDER_URL`, the composed flow
117
- `ARBITRUM_PROVIDER_URL` as well.
118
- `test_crosschain_readiness.py` checks the Ethereum-hub POC's live bridge and IPOR
119
- preconditions. Its `readiness` marker requires `--run-readiness`: ordinary runs
120
- exclude it even with `-m sdk`. Known HyperEVM gaps are non-strict xfails restricted
121
- to assertion failures, so availability improving is an XPASS, not broken CI.
122
- Readiness RPC clients fail on missing/unreachable providers or wrong chain IDs;
123
- they pin a snapshot per chain and do not require `eth_simulateV1`.
124
- `scripts/crosschain_readiness.py` separately reports both Arbitrum/HyperEVM USDC
125
- directions and the v3 factory pair's configuration (creation codes, routes, the
126
- dispatcher deployment gas limit, the canary creator's allowance, balance and HyperEVM
127
- big-block flag) with snapshot block numbers/hashes/timestamps. `hyperevm_delivery`
128
- flags manual execution into HyperEVM per message kind: `manual_execution_required` for
129
- commands and recalls (the hub route's `messageGasLimit`) and `dispatcher_deployment_manual`
130
- for the one-time deployment ticket. A delivery above the 3 M small block is manual
131
- unless every Chainlink executor seen delivering on HyperEVM's CCIP 2.0 OffRamp over
132
- the last ~2 weeks (`chainlink_executors`: `ExecutionStateChanged` senders from every
133
- source, the canary EOA excluded, at least 20 executions) sends into big blocks; a
134
- ticket below a dispatcher creation's gas is manual regardless. The executor set is
135
- derived on every run; `eth_usingBigBlocks` is read at the latest block.
136
- Blocked availability is a successful observation, not acceptance; incomplete probes
137
- fail. There is no GitHub workflow for it in this repository: run it locally with
138
- the Arbitrum and HyperEVM provider URLs from `.env`. A `Spoke` declares which transports reach it;
139
- the lifecycle matrix follows that.
96
+ runs one vault cycle; it skips without the source directory and needs
97
+ `HYPEREVM_PROVIDER_URL`.
140
98
 
141
99
  ## Conventions
142
100
 
@@ -237,6 +195,11 @@ the lifecycle matrix follows that.
237
195
 
238
196
  - `chains.py` chain registry; `market_ids.py` `IporFusionMarkets`; `types.py`; `errors.py`
239
197
  defines every SDK exception class (`tests/test_error_hierarchy.py` pins it)
198
+ - `fusion_errors.py` — `FUSION_ERROR_SIGNATURES`, every custom error of the
199
+ ipor-fusion contracts and their imports, registered by `errors.py` so reverts
200
+ decode by name; generated, never edited by hand: `uv run python
201
+ scripts/fusion_error_signatures.py ../ipor-fusion --source <commit>` (needs the
202
+ checkout's `npm ci`)
240
203
  - `about.py` — package version, repository URL, CHANGELOG parsing (`fusion changelog`,
241
204
  `server_info`); `field_docs.py` — `DOCS`, the JSON field descriptions shared by CLI
242
205
  output and MCP models
@@ -503,6 +503,55 @@ fails at run time:
503
503
  `dataclasses.asdict` form) with every field parsed; use it instead of
504
504
  `FusionInstance(**data)`, which passes raw strings into the role-typed fields.
505
505
 
506
+ #### Crosschain follows the released contracts
507
+
508
+ 4.0 encodes and decodes the crosschain contracts of the 2026-10-21 contracts
509
+ release (`ipor-abi`: the CCIP and Stargate factories, fuses and NAV pre-hook at
510
+ one CREATE3 address on Arbitrum and HyperEVM). Earlier crosschain deployments
511
+ are not supported: their fuses reject the new calldata, their envelopes fail
512
+ the version check, and their dispatcher `observation()` raises
513
+ `UnsupportedContractVersionError`, so an earlier-generation lane is unreadable
514
+ on the spoke side.
515
+
516
+ - **Envelopes.** `CODEC_VERSION` is 4 (Stargate), `CCIP_VERSION` 3.
517
+ - **`Command`.** New `min_execution_gas` before `action_data` (0 = the lane's
518
+ default, at most `MAX_COMMAND_EXECUTION_GAS`); `as_tuple()` / `from_tuple()`
519
+ have six members and `COMMAND_TUPLE_TYPE` is
520
+ `(bytes32,uint64,uint64,uint8,uint64,bytes)`.
521
+ - **REQUEST_SHARES.** `Command.request_shares(withdraw_manager, vault, shares,
522
+ max_fee_shares)`: the fee ceiling in shares is required (`NO_FEE_CEILING` for
523
+ none).
524
+ - **CCIP supply.** `CcipSendParams.min_delivered` is the delivered-amount floor
525
+ the supply `enter` carries (0 = none, at most the amount).
526
+ `CcipCommandType.CANCEL_DEPLOYMENT` cancels an expired dispatcher deployment.
527
+ - **Observations.** `CcipObservation` gains `unpriced_count` and
528
+ `unpriced_codes` (`unpriced_reason(index)` returns a `TrackedVaultPricing`); the
529
+ Stargate `Observation` gains `vault_valued` and `unpriced_count`;
530
+ `LaneObservation` gains `unpriced_count`.
531
+ - **Attestation.** `CrosschainLane.attestation(...)` takes `receipt_at`, the hub's
532
+ `LaneHubState.last_value_moving_receipt_at` (0 on Stargate). The executor
533
+ refuses an observation that is not strictly later than its last value-moving
534
+ receipt; the method raises `ValueError` for it and while a tracked vault is
535
+ unpriced. New: `LaneHubState.last_value_moving_receipt_at`,
536
+ `CrosschainLane.last_value_moving_receipt_at()` (`None` on Stargate) and
537
+ `CcipCrosschainExecutor.last_value_moving_receipt_at`.
538
+ - **Core.** `Call` gains an optional `decode_error` field: a wrapper maps an
539
+ undecodable answer to a named SDK exception (the earlier-generation
540
+ `observation()` raises `UnsupportedContractVersionError` this way), and it
541
+ survives `Call.map()`.
542
+ - **Removed.** `CrosschainDispatcher.pending_request_shares` (neither released
543
+ dispatcher has it). From the repository: `scripts/crosschain_readiness.py`, the
544
+ pytest `--run-readiness` option and `readiness` marker, and the examples
545
+ `crosschain_ccip_usdc_arbitrum_hyperevm.py` and
546
+ `composed_hypercore_flow_arbitrum_hyperevm.py`, which drove an earlier
547
+ deployment.
548
+ - **Events and errors.** `CCIP_EVENTS` mirrors the released contracts:
549
+ `ReturnFinalized` / `LateReturnFinalized` gain `debitedSD`, `SharesRequested`
550
+ gains `feeShares`, and new events are registered. The crosschain error registry
551
+ decodes every error the released contracts declare.
552
+ - **Routes.** The released CCIP README requires a route `messageGasLimit` of at
553
+ least 2.7 M for commands.
554
+
506
555
  ## Errors
507
556
 
508
557
  Every exception class the SDK defines now derives from `IporFusionError` and is
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev308
3
+ Version: 4.0.0.dev315
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
@@ -369,10 +369,12 @@ A flash-loan fuse also needs `update_callback_handler(handler, sender, selector)
369
369
 
370
370
  The full clone → configure → deposit → execute sequence is exercised in [`tests/test_simulate_vault_from_scratch_base.py`](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/tests/test_simulate_vault_from_scratch_base.py).
371
371
 
372
- Custom errors of the crosschain contracts decode by name: importing
373
- `ipor_fusion.crosschain` registers their signatures (`CROSSCHAIN_ERROR_SIGNATURES`),
374
- so a simulated or sent call that reverts reads `NavSettledStale(8453)` in
375
- `SimulationResult.revert_reason` and `TransactionError` instead of a bare selector.
372
+ Custom errors of the IPOR Fusion contracts and the libraries they import
373
+ (OpenZeppelin included) decode by name, so a simulated or sent call that reverts
374
+ reads `AccessManagedUnauthorized(0x...)`, `UnsupportedFuse()` or
375
+ `NavSettledStale(8453)` in `SimulationResult.revert_reason` and `TransactionError`
376
+ instead of a bare selector. Importing `ipor_fusion.crosschain` also registers
377
+ `CROSSCHAIN_ERROR_SIGNATURES`.
376
378
  `register_custom_errors([...])` adds your own, and `SimulationResult.raise_for_failure()`
377
379
  raises `SimulationError` naming the first failed call.
378
380
 
@@ -390,24 +392,11 @@ ever signed or broadcast.
390
392
  - [External-state margin leg](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/examples/external_state_margin_leg_base.py) — a vault whose capital
391
393
  sits off-chain: typed market-50 substrates, a dual-custodian propose/confirm marking the NAV,
392
394
  the scheduled-withdrawal prep an alpha performs, and a mismatched confirmation being rejected.
393
- - [Crosschain CCIP lifecycle](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py) (preview feature) — a vault
394
- whose capital works on another chain: supply USDC from an Arbitrum hub to a HyperEVM spoke
395
- over CCIP, attest the remote balance with two keys, deposit and redeem on the spoke, recall
396
- and claim, driven through `CrosschainLane` and relayed by `CrosschainSimulator`.
397
- - [Composed HyperCore flow](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/examples/composed_hypercore_flow_arbitrum_hyperevm.py) (preview feature) — the
398
- same hub funding a HyperCore vault (market 55) that trades on Hyperliquid Core: the Core leg
399
- (bridge, dex transfer, order, close, exit) built from the vault's substrate grants and estimated
400
- with `eth_estimateGas` at head (EVM acceptance only, Core executes later), the REDEEM sized by the vault's EVM exit ceiling behind the executor's
401
- fee gate, then recall, residual attestation and claim replayed in `CrosschainSimulator` at
402
- blocks pinned inside the second live cycle.
403
-
404
395
  ```bash
405
396
  export BASE_PROVIDER_URL="https://base-mainnet.g.alchemy.com/v2/YOUR_KEY"
406
397
  uv run python examples/simple_aave_v3_supply_base.py
407
398
  uv run python examples/advanced_euler_v2_credit_market_base.py
408
399
  uv run python examples/external_state_margin_leg_base.py
409
- uv run python examples/crosschain_ccip_usdc_arbitrum_hyperevm.py # needs ARBITRUM_PROVIDER_URL and HYPEREVM_PROVIDER_URL
410
- uv run python examples/composed_hypercore_flow_arbitrum_hyperevm.py # same two providers
411
400
  ```
412
401
 
413
402
  No RPC key? `BASE_PROVIDER_URL=https://mainnet.base.org` (Base's public RPC) runs the examples out of
@@ -528,12 +517,12 @@ the pilot executors and factories). Pin an exact version if you depend on them.
528
517
  | Crosschain fuses (market 54): `StargateCrosschainSupplyFuse`, `StargateCrosschainCommandFuse`, `CcipCrosschainSupplyFuse`, `CcipCrosschainCommandFuse`, `CrosschainClaimFuse`; transport-agnostic bases `CrosschainSupplyFuse` / `CrosschainCommandFuse` with `StargateSendParams` / `CcipSendParams`, plus `Command`, `CrosschainSubstrateLib`, `OptionsBuilder` | `ipor_fusion.crosschain` |
529
518
  | HyperCore fuses (market 55): `HyperCoreDepositFuse`, `HyperCoreMarginFuse`, `HyperCoreSendFuse`, `HyperCoreOrderFuse`, `HyperCoreCancelFuse`, `HyperCoreBuilderFeeFuse`, `HyperCoreSubstrates` | `ipor_fusion.hypercore`, with `HyperCoreReader`, `read_hypercore_vault_state` and the event decoders |
530
519
 
531
- The mainnet crosschain POC vault uses a keccak-derived market ID, not 54. Pass
532
- `market_id=crosschain_market_id("IPOR_FUSION_CROSSCHAIN_USDC_POC_V1")` to `open_lane`
533
- / `discover_deployment` for that deployment. Both require it explicitly:
534
- `discover_deployment` reads the market's executor grants; `open_lane` takes an executor
535
- address and uses the market ID to find the vault's matching fuses unless they are
536
- passed.
520
+ The crosschain API supports only the contracts of the 2026-10-21 release; earlier
521
+ deployments are unreadable (`MIGRATION_4.md`). `open_lane` and `discover_deployment`
522
+ take the market ID explicitly (54, or a keccak-derived one from
523
+ `crosschain_market_id(name)` for a vault built with its own): `discover_deployment`
524
+ reads the market's executor grants; `open_lane` takes an executor address and uses the
525
+ market ID to find the vault's matching fuses unless they are passed.
537
526
 
538
527
  ### Readers (`ipor_fusion.readers`)
539
528
 
@@ -320,10 +320,12 @@ A flash-loan fuse also needs `update_callback_handler(handler, sender, selector)
320
320
 
321
321
  The full clone → configure → deposit → execute sequence is exercised in [`tests/test_simulate_vault_from_scratch_base.py`](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/tests/test_simulate_vault_from_scratch_base.py).
322
322
 
323
- Custom errors of the crosschain contracts decode by name: importing
324
- `ipor_fusion.crosschain` registers their signatures (`CROSSCHAIN_ERROR_SIGNATURES`),
325
- so a simulated or sent call that reverts reads `NavSettledStale(8453)` in
326
- `SimulationResult.revert_reason` and `TransactionError` instead of a bare selector.
323
+ Custom errors of the IPOR Fusion contracts and the libraries they import
324
+ (OpenZeppelin included) decode by name, so a simulated or sent call that reverts
325
+ reads `AccessManagedUnauthorized(0x...)`, `UnsupportedFuse()` or
326
+ `NavSettledStale(8453)` in `SimulationResult.revert_reason` and `TransactionError`
327
+ instead of a bare selector. Importing `ipor_fusion.crosschain` also registers
328
+ `CROSSCHAIN_ERROR_SIGNATURES`.
327
329
  `register_custom_errors([...])` adds your own, and `SimulationResult.raise_for_failure()`
328
330
  raises `SimulationError` naming the first failed call.
329
331
 
@@ -341,24 +343,11 @@ ever signed or broadcast.
341
343
  - [External-state margin leg](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/examples/external_state_margin_leg_base.py) — a vault whose capital
342
344
  sits off-chain: typed market-50 substrates, a dual-custodian propose/confirm marking the NAV,
343
345
  the scheduled-withdrawal prep an alpha performs, and a mismatched confirmation being rejected.
344
- - [Crosschain CCIP lifecycle](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py) (preview feature) — a vault
345
- whose capital works on another chain: supply USDC from an Arbitrum hub to a HyperEVM spoke
346
- over CCIP, attest the remote balance with two keys, deposit and redeem on the spoke, recall
347
- and claim, driven through `CrosschainLane` and relayed by `CrosschainSimulator`.
348
- - [Composed HyperCore flow](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/examples/composed_hypercore_flow_arbitrum_hyperevm.py) (preview feature) — the
349
- same hub funding a HyperCore vault (market 55) that trades on Hyperliquid Core: the Core leg
350
- (bridge, dex transfer, order, close, exit) built from the vault's substrate grants and estimated
351
- with `eth_estimateGas` at head (EVM acceptance only, Core executes later), the REDEEM sized by the vault's EVM exit ceiling behind the executor's
352
- fee gate, then recall, residual attestation and claim replayed in `CrosschainSimulator` at
353
- blocks pinned inside the second live cycle.
354
-
355
346
  ```bash
356
347
  export BASE_PROVIDER_URL="https://base-mainnet.g.alchemy.com/v2/YOUR_KEY"
357
348
  uv run python examples/simple_aave_v3_supply_base.py
358
349
  uv run python examples/advanced_euler_v2_credit_market_base.py
359
350
  uv run python examples/external_state_margin_leg_base.py
360
- uv run python examples/crosschain_ccip_usdc_arbitrum_hyperevm.py # needs ARBITRUM_PROVIDER_URL and HYPEREVM_PROVIDER_URL
361
- uv run python examples/composed_hypercore_flow_arbitrum_hyperevm.py # same two providers
362
351
  ```
363
352
 
364
353
  No RPC key? `BASE_PROVIDER_URL=https://mainnet.base.org` (Base's public RPC) runs the examples out of
@@ -479,12 +468,12 @@ the pilot executors and factories). Pin an exact version if you depend on them.
479
468
  | Crosschain fuses (market 54): `StargateCrosschainSupplyFuse`, `StargateCrosschainCommandFuse`, `CcipCrosschainSupplyFuse`, `CcipCrosschainCommandFuse`, `CrosschainClaimFuse`; transport-agnostic bases `CrosschainSupplyFuse` / `CrosschainCommandFuse` with `StargateSendParams` / `CcipSendParams`, plus `Command`, `CrosschainSubstrateLib`, `OptionsBuilder` | `ipor_fusion.crosschain` |
480
469
  | HyperCore fuses (market 55): `HyperCoreDepositFuse`, `HyperCoreMarginFuse`, `HyperCoreSendFuse`, `HyperCoreOrderFuse`, `HyperCoreCancelFuse`, `HyperCoreBuilderFeeFuse`, `HyperCoreSubstrates` | `ipor_fusion.hypercore`, with `HyperCoreReader`, `read_hypercore_vault_state` and the event decoders |
481
470
 
482
- The mainnet crosschain POC vault uses a keccak-derived market ID, not 54. Pass
483
- `market_id=crosschain_market_id("IPOR_FUSION_CROSSCHAIN_USDC_POC_V1")` to `open_lane`
484
- / `discover_deployment` for that deployment. Both require it explicitly:
485
- `discover_deployment` reads the market's executor grants; `open_lane` takes an executor
486
- address and uses the market ID to find the vault's matching fuses unless they are
487
- passed.
471
+ The crosschain API supports only the contracts of the 2026-10-21 release; earlier
472
+ deployments are unreadable (`MIGRATION_4.md`). `open_lane` and `discover_deployment`
473
+ take the market ID explicitly (54, or a keccak-derived one from
474
+ `crosschain_market_id(name)` for a vault built with its own): `discover_deployment`
475
+ reads the market's executor grants; `open_lane` takes an executor address and uses the
476
+ market ID to find the vault's matching fuses unless they are passed.
488
477
 
489
478
  ### Readers (`ipor_fusion.readers`)
490
479
 
@@ -38,29 +38,6 @@ transaction.
38
38
  brings the margin home and releases it for a user's scheduled withdrawal, then
39
39
  demonstrates the executor rejecting a confirmation that does not match its
40
40
  proposal.
41
- - [`crosschain_ccip_usdc_arbitrum_hyperevm.py`](crosschain_ccip_usdc_arbitrum_hyperevm.py) --
42
- a vault whose capital works on another chain. Opens a `CrosschainLane` on a
43
- live Arbitrum hub vault whose executor has a dispatcher on HyperEVM, then
44
- drives the whole lifecycle over CCIP: supply USDC to the spoke, have a
45
- proposer and an approver attest the dispatcher's balance into the hub NAV,
46
- DEPOSIT into and REDEEM from the spoke vault by command, re-attest, recall
47
- the idle to the hub and claim it back into the vault. Both chains run under
48
- `eth_simulateV1` and `CrosschainSimulator` relays each CCIP message between
49
- them, so it needs an Arbitrum and a HyperEVM archive RPC.
50
- - [`composed_hypercore_flow_arbitrum_hyperevm.py`](composed_hypercore_flow_arbitrum_hyperevm.py) --
51
- the composed flow: the same Arbitrum hub funding a HyperCore vault on
52
- HyperEVM (a Plasma Vault that is itself a Hyperliquid Core account) and the
53
- trade inside it. Part A builds the Core leg from the vault's market-55
54
- substrate grants (bridge EVM -> Core, spot -> perp dex, a limit order and its
55
- reduce-only close, dex -> spot, Core -> EVM) and estimates each action with
56
- `eth_estimateGas` at head -- six independent previews, EVM acceptance only --
57
- with a balance override where the vault holds no USDC and sized to the live
58
- Core inventory where the fuse checks a Core balance or dex equity, because
59
- `eth_simulateV1` cannot run the HyperCore precompiles.
60
- Part B replays the hub legs of the second live cycle in `CrosschainSimulator`
61
- at pinned blocks: the REDEEM sized by `read_hypercore_evm_exit_ceiling` behind
62
- the executor's maxFee gate, then recall, token return, the residual
63
- attestation and the claim. Nothing is signed; it needs the same two RPCs.
64
41
 
65
42
  ## Prerequisites
66
43
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.0.0.dev308"
3
+ version = "4.0.0.dev315"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -4,7 +4,6 @@ log_cli_level = INFO
4
4
  addopts = --cov=src/ipor_fusion --cov-report=term-missing --cov-report=xml:coverage.xml
5
5
  testpaths = tests
6
6
  markers =
7
- readiness: live crosschain availability checks (requires --run-readiness; excluded by default)
8
7
  sdk: SDK core and fuse tests (integration ones need *_PROVIDER_URL, auto-skip otherwise)
9
8
  cli: CLI unit tests (no network required)
10
9
  mcp: MCP server tests (no network required)
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env python3
2
+ """Regenerate ``src/ipor_fusion/fusion_errors.py`` from an ipor-fusion checkout.
3
+
4
+ Collects every ``error`` declaration of the Solidity files reachable by import
5
+ from ``contracts/`` (the contracts and the libraries they import, OpenZeppelin
6
+ included, resolved through the checkout's ``foundry.toml`` remappings) and
7
+ writes them as
8
+ canonical ``Name(type,...)`` signatures: enums become ``uint8``, contract,
9
+ interface and library types ``address``, ``uint``/``int`` their 256-bit form.
10
+ Any other parameter type (a struct, a user-defined value type) stops the run,
11
+ because its canonical form needs the compiler.
12
+
13
+ uv run python scripts/fusion_error_signatures.py ../ipor-fusion --source <commit>
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import argparse
19
+ import re
20
+ import sys
21
+ import tomllib
22
+ from pathlib import Path
23
+
24
+ _OUTPUT = Path(__file__).resolve().parent.parent / "src/ipor_fusion/fusion_errors.py"
25
+ _IMPORT = re.compile(r'^\s*import\s+(?:[^"\']*\s+from\s+)?["\']([^"\']+)["\']', re.M)
26
+ _ERROR = re.compile(r"\berror\s+(\w+)\s*\(([^)]*)\)\s*;")
27
+ _ENUM = re.compile(r"\benum\s+(\w+)")
28
+ _CONTRACT = re.compile(r"\b(?:abstract\s+)?(?:contract|interface|library)\s+(\w+)")
29
+ _ELEMENTARY = re.compile(
30
+ r"^(address|bool|string|bytes([1-9]|[12]\d|3[0-2])?|u?int(8|16|24|32|40|48|56|64"
31
+ r"|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224"
32
+ r"|232|240|248|256)?)$"
33
+ )
34
+ _COMMENTS = re.compile(r"//[^\n]*|/\*.*?\*/", re.S)
35
+
36
+
37
+ class _Resolver:
38
+ """Forge's import resolution: relative paths, then the longest matching
39
+ remapping, then the checkout root and each ``libs`` directory."""
40
+
41
+ def __init__(self, root: Path) -> None:
42
+ profile = tomllib.loads((root / "foundry.toml").read_text())["profile"]
43
+ default = profile["default"]
44
+ pairs = [entry.split("=", 1) for entry in default["remappings"]]
45
+ self._root = root
46
+ self._remappings = sorted(pairs, key=lambda pair: -len(pair[0]))
47
+ self._bases = [root, *(root / lib for lib in default["libs"])]
48
+
49
+ def __call__(self, spec: str, importer: Path) -> Path:
50
+ if spec.startswith("."):
51
+ return (importer.parent / spec).resolve()
52
+ for prefix, target in self._remappings:
53
+ if spec.startswith(prefix):
54
+ return (self._root / (target + spec.removeprefix(prefix))).resolve()
55
+ for base in self._bases:
56
+ if (base / spec).is_file():
57
+ return (base / spec).resolve()
58
+ return (self._root / spec).resolve()
59
+
60
+
61
+ def _closure(root: Path) -> dict[Path, str]:
62
+ resolve = _Resolver(root)
63
+ pending = sorted((root / "contracts").rglob("*.sol"))
64
+ sources: dict[Path, str] = {}
65
+ while pending:
66
+ path = pending.pop()
67
+ if path in sources:
68
+ continue
69
+ if not path.is_file():
70
+ raise SystemExit(f"unresolved import: {path}")
71
+ text = _COMMENTS.sub("", path.read_text())
72
+ sources[path] = text
73
+ pending.extend(resolve(spec, path) for spec in _IMPORT.findall(text))
74
+ return sources
75
+
76
+
77
+ def _canonical(param: str, enums: set[str], contracts: set[str], where: str) -> str:
78
+ kind = param.split()[0].split(".")[-1]
79
+ if kind in ("uint", "int"):
80
+ return f"{kind}256"
81
+ if _ELEMENTARY.fullmatch(kind):
82
+ return kind
83
+ if kind in enums:
84
+ return "uint8"
85
+ if kind in contracts:
86
+ return "address"
87
+ raise SystemExit(f"{where}: no canonical form for parameter type {kind!r}")
88
+
89
+
90
+ def collect(root: Path) -> list[str]:
91
+ sources = _closure(root)
92
+ enums = {name for text in sources.values() for name in _ENUM.findall(text)}
93
+ contracts = {name for text in sources.values() for name in _CONTRACT.findall(text)}
94
+ signatures: set[str] = set()
95
+ for path, text in sources.items():
96
+ for name, params in _ERROR.findall(text):
97
+ types = [
98
+ _canonical(p.strip(), enums, contracts, f"{path}: {name}")
99
+ for p in params.split(",")
100
+ if p.strip()
101
+ ]
102
+ signatures.add(f"{name}({','.join(types)})")
103
+ return sorted(signatures)
104
+
105
+
106
+ def render(signatures: list[str], source: str) -> str:
107
+ lines = "\n".join(f' "{signature}",' for signature in signatures)
108
+ return f'''"""Custom errors of the IPOR Fusion contracts and the libraries they import
109
+ (OpenZeppelin included), registered by :mod:`ipor_fusion.errors` so revert data
110
+ decodes by name (``AccessManagedUnauthorized(0x...)``, ``UnsupportedFuse()``)
111
+ instead of a bare selector.
112
+
113
+ Generated by ``scripts/fusion_error_signatures.py`` from ipor-fusion {source};
114
+ do not edit by hand.
115
+ """
116
+
117
+ #: ``Name(type,...)`` signatures, sorted; the selector is the keccak of each.
118
+ FUSION_ERROR_SIGNATURES: tuple[str, ...] = (
119
+ {lines}
120
+ )
121
+ '''
122
+
123
+
124
+ def main() -> None:
125
+ parser = argparse.ArgumentParser(description="Regenerate fusion_errors.py.")
126
+ parser.add_argument("checkout", type=Path, help="ipor-fusion checkout")
127
+ parser.add_argument(
128
+ "--source", required=True, help="what the checkout is, e.g. a commit"
129
+ )
130
+ args = parser.parse_args()
131
+ signatures = collect(args.checkout.resolve())
132
+ _OUTPUT.write_text(render(signatures, args.source))
133
+ print(f"{len(signatures)} signatures -> {_OUTPUT}", file=sys.stderr)
134
+
135
+
136
+ if __name__ == "__main__":
137
+ main()
@@ -5,6 +5,7 @@ from dataclasses import dataclass
5
5
  from typing import Generic, TypeVar, cast
6
6
 
7
7
  from eth_abi import decode, encode
8
+ from eth_abi.exceptions import DecodingError
8
9
  from eth_typing import ChecksumAddress
9
10
  from eth_utils import function_signature_to_4byte_selector
10
11
  from web3 import Web3
@@ -53,6 +54,9 @@ class Call(Generic[T_co]):
53
54
  data: bytes
54
55
  output_types: Sequence[str] | None = None
55
56
  decoder: Callable[..., T_co] | None = None
57
+ #: Turns an ABI decoding failure of the return data into a named error
58
+ #: (for a contract build whose return layout differs); ``None`` re-raises.
59
+ decode_error: Callable[[DecodingError], Exception] | None = None
56
60
 
57
61
  def __post_init__(self) -> None:
58
62
  if self.output_types is not None:
@@ -81,6 +85,7 @@ class Call(Generic[T_co]):
81
85
  data=self.data,
82
86
  output_types=self.output_types,
83
87
  decoder=mapped,
88
+ decode_error=self.decode_error,
84
89
  )
85
90
 
86
91
  def call(self, ctx: Web3Context, *, block: BlockIdentifier | None = None) -> T_co:
@@ -112,7 +117,12 @@ class Call(Generic[T_co]):
112
117
  of `.call(ctx)`, for return data fetched elsewhere (e.g. `Multicall3`)."""
113
118
  if not self.output_types:
114
119
  raise ValueError("Call.decode() on a write-only Call.")
115
- values = tuple(decode(self.output_types, bytes(raw)))
120
+ try:
121
+ values = tuple(decode(self.output_types, bytes(raw)))
122
+ except DecodingError as exc:
123
+ if self.decode_error is None:
124
+ raise
125
+ raise self.decode_error(exc) from exc
116
126
  single: object = values[0] if len(values) == 1 else values
117
127
  if self.decoder is not None:
118
128
  return self.decoder(single)
@@ -163,12 +173,14 @@ class ContractWrapper:
163
173
  *args: object,
164
174
  output_types: Sequence[str],
165
175
  decoder: Callable[..., T] | None = None,
176
+ decode_error: Callable[[DecodingError], Exception] | None = None,
166
177
  ) -> Call[T]:
167
178
  return Call(
168
179
  to=self._address,
169
180
  data=_encode_calldata(signature, *args),
170
181
  output_types=output_types,
171
182
  decoder=decoder,
183
+ decode_error=decode_error,
172
184
  )
173
185
 
174
186
  def _write(self, signature: str, *args: object) -> Call[None]:
@@ -110,6 +110,8 @@ from ipor_fusion.crosschain.messages import (
110
110
  CCIP_VERSION,
111
111
  CODEC_VERSION,
112
112
  EMPTY_COMMAND,
113
+ MAX_COMMAND_EXECUTION_GAS,
114
+ NO_FEE_CEILING,
113
115
  BusinessAction,
114
116
  CcipMsgType,
115
117
  Command,
@@ -117,6 +119,7 @@ from ipor_fusion.crosschain.messages import (
117
119
  CrosschainTransportKind,
118
120
  DeploymentStatus,
119
121
  MsgType,
122
+ TrackedVaultPricing,
120
123
  decode_ccip_envelope,
121
124
  decode_command,
122
125
  decode_envelope,
@@ -254,6 +257,9 @@ __all__ = [
254
257
  "CrosschainTransportKind",
255
258
  "DeploymentStatus",
256
259
  "EMPTY_COMMAND",
260
+ "MAX_COMMAND_EXECUTION_GAS",
261
+ "NO_FEE_CEILING",
262
+ "TrackedVaultPricing",
257
263
  "EVMTokenAmount",
258
264
  "EnforcedOptionParam",
259
265
  "ExecutorInitParams",