ipor-fusion 4.0.0.dev30__tar.gz → 4.0.0.dev35__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 (285) hide show
  1. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/AGENTS.md +3 -1
  2. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/PKG-INFO +1 -1
  3. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +19 -10
  4. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/examples/external_state_margin_leg_base.py +2 -2
  5. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/pyproject.toml +1 -1
  6. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/__init__.py +20 -0
  7. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/market_cmd.py +18 -26
  8. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/context.py +3 -3
  9. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/external_state_executor.py +29 -27
  10. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/errors.py +3 -1
  11. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/explorer.py +6 -5
  12. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/external_state_events.py +6 -4
  13. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/hypercore.py +39 -20
  14. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/market_info.py +3 -3
  15. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/mcp/server.py +4 -9
  16. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/morpho_api.py +20 -13
  17. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/hypercore.py +27 -17
  18. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/hypercore_outcome.py +4 -3
  19. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/lending_health.py +8 -4
  20. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/substrates.py +2 -2
  21. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/types.py +35 -2
  22. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/vault_data.py +7 -4
  23. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_market_morpho_blue.py +3 -1
  24. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_web3_context.py +1 -1
  25. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/typed_client/consumer.py +3 -1
  26. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.claude-plugin/marketplace.json +0 -0
  27. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.claude-plugin/plugin.json +0 -0
  28. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.env.example +0 -0
  29. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.gemini/settings.json +0 -0
  30. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.git-blame-ignore-revs +0 -0
  31. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.github/workflows/cd.yml +0 -0
  32. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.github/workflows/ci.yml +0 -0
  33. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.github/workflows/commit-lint.yml +0 -0
  34. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.github/workflows/notify-slack.yml +0 -0
  35. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.github/workflows/python-build.yml +0 -0
  36. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.github/workflows/python-publish.yml +0 -0
  37. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.github/workflows/release.yml +0 -0
  38. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.github/workflows/report-slack.yml +0 -0
  39. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.gitignore +0 -0
  40. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.mcp.json +0 -0
  41. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.pre-commit-config.yaml +0 -0
  42. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/.python-version +0 -0
  43. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/CHANGELOG.md +0 -0
  44. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/CLAUDE.md +0 -0
  45. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/CODEOWNERS +0 -0
  46. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/LICENSE +0 -0
  47. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/README.md +0 -0
  48. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/build.sh +0 -0
  49. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/examples/CONTRIBUTING.md +0 -0
  50. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/examples/README.md +0 -0
  51. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  52. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  53. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  54. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/examples/simple_aave_v3_supply_base.py +0 -0
  55. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/pytest.ini +0 -0
  56. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/scripts/commit-check.sh +0 -0
  57. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/scripts/crosschain_readiness.py +0 -0
  58. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/skills/ipor-deploy-vault/SKILL.md +0 -0
  59. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/about.py +0 -0
  60. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cache.py +0 -0
  61. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/chains.py +0 -0
  62. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/__init__.py +0 -0
  63. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  64. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/config_cmd.py +0 -0
  65. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/config_store.py +0 -0
  66. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/main.py +0 -0
  67. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/options.py +0 -0
  68. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  69. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  70. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/vault_health.py +0 -0
  71. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  72. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  73. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  74. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/config/__init__.py +0 -0
  75. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/config/roles.py +0 -0
  76. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/__init__.py +0 -0
  77. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/access.py +0 -0
  78. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/address.py +0 -0
  79. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/contract.py +0 -0
  80. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/erc20.py +0 -0
  81. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/fee_manager.py +0 -0
  82. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/fuse_action.py +0 -0
  83. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/fusion_factory.py +0 -0
  84. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/logs.py +0 -0
  85. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/multicall.py +0 -0
  86. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/oracle.py +0 -0
  87. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/plasma_vault.py +0 -0
  88. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/rewards_manager.py +0 -0
  89. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/simulation.py +0 -0
  90. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  91. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/__init__.py +0 -0
  92. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  93. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  94. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  95. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  96. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  97. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  98. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  99. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  100. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  101. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/contracts.py +0 -0
  102. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/discovery.py +0 -0
  103. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/errors.py +0 -0
  104. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/lane.py +0 -0
  105. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/logs.py +0 -0
  106. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/messages.py +0 -0
  107. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/simulation.py +0 -0
  108. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  109. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  110. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  111. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  112. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  113. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/crosschain/transport.py +0 -0
  114. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/dependency_graph.py +0 -0
  115. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/entry_cli.py +0 -0
  116. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/entry_mcp.py +0 -0
  117. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/field_docs.py +0 -0
  118. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/__init__.py +0 -0
  119. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  120. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/async_action.py +0 -0
  121. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/base.py +0 -0
  122. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  123. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/crosschain/__init__.py +0 -0
  124. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/crosschain/base.py +0 -0
  125. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/crosschain/ccip.py +0 -0
  126. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/crosschain/stargate.py +0 -0
  127. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/erc4626.py +0 -0
  128. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  129. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/events.py +0 -0
  130. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/external_state.py +0 -0
  131. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  132. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  133. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
  134. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/merkl.py +0 -0
  135. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/morpho.py +0 -0
  136. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  137. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  138. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/fuses/universal.py +0 -0
  139. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/guide/__init__.py +0 -0
  140. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/guide/architecture.md +0 -0
  141. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/guide/glossary.md +0 -0
  142. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/guide/invariants.md +0 -0
  143. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/guide/quickstart.md +0 -0
  144. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/market_ids.py +0 -0
  145. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/mcp/__init__.py +0 -0
  146. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/mcp/guide.py +0 -0
  147. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/mcp/models.py +0 -0
  148. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/py.typed +0 -0
  149. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/__init__.py +0 -0
  150. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/aave_v3.py +0 -0
  151. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/aave_v4.py +0 -0
  152. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/compound_v3.py +0 -0
  153. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/morpho.py +0 -0
  154. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  155. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/position_manager.py +0 -0
  156. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  157. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  158. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/readers/unpriceable.py +0 -0
  159. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/validation.py +0 -0
  160. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/src/ipor_fusion/vault_info.py +0 -0
  161. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/UniswapV3UniversalRouter.py +0 -0
  162. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_crosschain.py +0 -0
  163. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_crosschain_lifecycle.py +0 -0
  164. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_crosschain_recovery.py +0 -0
  165. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_euler_v2.py +0 -0
  166. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_foundry.py +0 -0
  167. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_guide.py +0 -0
  168. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_hypercore_model.py +0 -0
  169. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_hypercore_shadow.py +0 -0
  170. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_multicall.py +0 -0
  171. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_simulate.py +0 -0
  172. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/_validation.py +0 -0
  173. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/addresses.py +0 -0
  174. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/conftest.py +0 -0
  175. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/constants.py +0 -0
  176. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  177. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/fixtures/hypercore_market55.json +0 -0
  178. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/fixtures/vault_info_golden/clean.json +0 -0
  179. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  180. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/fixtures/vault_info_golden/rich.json +0 -0
  181. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  182. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_about.py +0 -0
  183. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_access_manager.py +0 -0
  184. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cache.py +0 -0
  185. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_chains.py +0 -0
  186. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_changelog.py +0 -0
  187. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_commands.py +0 -0
  188. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_config_store.py +0 -0
  189. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_helpers.py +0 -0
  190. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_hypercore.py +0 -0
  191. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_lending_health.py +0 -0
  192. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_oracle_mapping.py +0 -0
  193. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_pending_requests_scan.py +0 -0
  194. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_role_accounts.py +0 -0
  195. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_vault_info_golden.py +0 -0
  196. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_vault_predates_getters.py +0 -0
  197. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_cli_vault_validate.py +0 -0
  198. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_contract_call.py +0 -0
  199. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_contract_encoder.py +0 -0
  200. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_ccip_events.py +0 -0
  201. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_ccip_indexer.py +0 -0
  202. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_ccip_quote.py +0 -0
  203. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_chainlink.py +0 -0
  204. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_contracts.py +0 -0
  205. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_encoding.py +0 -0
  206. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_errors.py +0 -0
  207. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_lane.py +0 -0
  208. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_layering.py +0 -0
  209. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_readiness.py +0 -0
  210. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_readiness_report.py +0 -0
  211. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_crosschain_transport.py +0 -0
  212. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_erc20.py +0 -0
  213. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_examples_composed_hypercore.py +0 -0
  214. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_examples_crosschain.py +0 -0
  215. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  216. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_examples_vaults.py +0 -0
  217. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_explorer.py +0 -0
  218. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_external_state_events.py +0 -0
  219. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_external_state_executor.py +0 -0
  220. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_fee_manager.py +0 -0
  221. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_fuse_encoding.py +0 -0
  222. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_guide.py +0 -0
  223. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_hypercore_deployment.py +0 -0
  224. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_hypercore_events.py +0 -0
  225. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_hypercore_flow.py +0 -0
  226. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_hypercore_live.py +0 -0
  227. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_hypercore_outcome.py +0 -0
  228. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_hypercore_readers.py +0 -0
  229. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_hypercore_simulation.py +0 -0
  230. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_logs.py +0 -0
  231. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_mcp_hypercore.py +0 -0
  232. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_mcp_models.py +0 -0
  233. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_mcp_server.py +0 -0
  234. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_mcp_vault_validate.py +0 -0
  235. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_multicall.py +0 -0
  236. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_oracle.py +0 -0
  237. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_oracle_mapping.py +0 -0
  238. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_plasma_vault.py +0 -0
  239. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_reader_encoding.py +0 -0
  240. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_readiness_selection.py +0 -0
  241. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_revert_decoding.py +0 -0
  242. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_rewards_manager.py +0 -0
  243. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_roles.py +0 -0
  244. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_sdk_layering.py +0 -0
  245. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  246. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  247. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  248. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_crosschain_canary.py +0 -0
  249. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_crosschain_hypercore.py +0 -0
  250. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  251. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  252. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  253. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  254. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  255. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  256. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  257. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_examples_arbitrum.py +0 -0
  258. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_examples_base.py +0 -0
  259. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_examples_crosschain.py +0 -0
  260. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_external_state_executor_base.py +0 -0
  261. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  262. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  263. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  264. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_morpho_blue.py +0 -0
  265. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_pilot_v3.py +0 -0
  266. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  267. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  268. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  269. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  270. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_readers_integration.py +0 -0
  271. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_release_funds.py +0 -0
  272. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_swap_on_base.py +0 -0
  273. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  274. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_solidity_compiler.py +0 -0
  275. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_solidity_mirrors.py +0 -0
  276. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_substrates.py +0 -0
  277. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_types_and_events.py +0 -0
  278. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_unpriceable_tokens.py +0 -0
  279. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_validation.py +0 -0
  280. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_vault_dep_graph.py +0 -0
  281. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_vault_info_onchain_base.py +0 -0
  282. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  283. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_vault_simulator_blocks.py +0 -0
  284. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/tests/test_withdraw_manager.py +0 -0
  285. {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev35}/uv.lock +0 -0
@@ -285,7 +285,9 @@ or examples.
285
285
  `MarketId`, ...) name the unit, and nothing scales by decimals.
286
286
  - Ids and addresses are nominal in every signature: `ChainId`, `MarketId` (each
287
287
  `IporFusionMarkets` member is one), `RoleId | Roles`, `ChecksumAddress`;
288
- `HexAddress` only for the lowercase addresses decoded from substrates. Raw input
288
+ `HexAddress` only for the lowercase addresses decoded from substrates;
289
+ `MorphoBlueMarketId` is always `0x` + 64 lowercase hex, built by
290
+ `parse_morpho_market_id`. Raw input
289
291
  is parsed once at the boundary (click param types, MCP tools, the user config).
290
292
  `src/`, `examples/` and `tests/typed_client/` are checked with
291
293
  `reportArgumentType` on, so a bare `int`/`str` passed for one fails pyright; the
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev30
3
+ Version: 4.0.0.dev35
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
@@ -100,12 +100,21 @@ from ipor_fusion.fuses import (
100
100
  from ipor_fusion.fuses.hypercore import (
101
101
  SPOT_DEX,
102
102
  USDC_SYSTEM_ADDRESS,
103
+ USDC_TOKEN_INDEX,
103
104
  TimeInForce,
104
105
  read_index_of,
105
106
  )
106
107
  from ipor_fusion.market_ids import IporFusionMarkets
107
108
  from ipor_fusion.readers.hypercore import HyperCoreReader
108
- from ipor_fusion.types import Amount, ChainId, MarketId, Period, Shares
109
+ from ipor_fusion.types import (
110
+ Amount,
111
+ ChainId,
112
+ HyperCoreAsset,
113
+ HyperCoreClientOrderId,
114
+ MarketId,
115
+ Period,
116
+ Shares,
117
+ )
109
118
 
110
119
  log = logging.getLogger("composed_hypercore_flow_arbitrum_hyperevm")
111
120
 
@@ -181,7 +190,7 @@ BRIDGE_LATENCY = Period(2 * 60)
181
190
  # ── The trade the live cycle ran ─────────────────────────────────────────────
182
191
  # xyz is HIP-3 perp dex 1; xyz:NVDA is action asset 100_000 + 1 * 10_000 + 2.
183
192
  XYZ_DEX = 1
184
- XYZ_NVDA_ASSET = 110_002
193
+ XYZ_NVDA_ASSET = HyperCoreAsset(110_002)
185
194
  # Core amounts are Core wei: 8 decimals for USDC; sizes carry 8 implied
186
195
  # decimals too (0.05 NVDA = 5_000_000), prices 8 implied decimals.
187
196
  CORE_WEI = 10**8
@@ -410,9 +419,9 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
410
419
  state = read_hypercore_vault_state(ctx, HYPERCORE_VAULT, HYPERCORE_BALANCE_FUSE)
411
420
  reader = HyperCoreReader(ctx)
412
421
  pending = bool(state.pending and state.pending.pending)
413
- spot = reader.spot_balance(HYPERCORE_VAULT, 0).call()
422
+ spot = reader.spot_balance(HYPERCORE_VAULT, USDC_TOKEN_INDEX).call()
414
423
  spot_available = _available_spot_wei(spot.total, spot.hold)
415
- usdc_info = reader.token_info(0).call()
424
+ usdc_info = reader.token_info(USDC_TOKEN_INDEX).call()
416
425
  evm_step = 10 ** max(int(usdc_info.wei_decimals) - 6, 0)
417
426
  xyz_equity_usd6 = int(
418
427
  reader.account_margin_summary(XYZ_DEX, HYPERCORE_VAULT).call().account_value
@@ -454,7 +463,7 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
454
463
  web3_hype,
455
464
  vault,
456
465
  "bridge_to_core",
457
- deposit_fuse.enter(token_index=0, amount=BRIDGE_AMOUNT_USDC),
466
+ deposit_fuse.enter(token_index=USDC_TOKEN_INDEX, amount=BRIDGE_AMOUNT_USDC),
458
467
  override=override,
459
468
  note="14 USDC EVM -> Core spot through the CoreDepositWallet; vault USDC balance overridden for the preview",
460
469
  )
@@ -472,7 +481,7 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
472
481
  destination=HYPERCORE_VAULT,
473
482
  source_dex=SPOT_DEX,
474
483
  destination_dex=XYZ_DEX,
475
- token_index=0,
484
+ token_index=USDC_TOKEN_INDEX,
476
485
  amount_wei=to_dex,
477
486
  ),
478
487
  override=None,
@@ -511,7 +520,7 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
511
520
  limit_px=limit_buy,
512
521
  sz=ORDER_SIZE,
513
522
  tif=TimeInForce.IOC,
514
- cloid=1,
523
+ cloid=HyperCoreClientOrderId(1),
515
524
  ),
516
525
  override=None,
517
526
  note=f"buy 0.05 xyz:NVDA, limit {limit_buy} (mark +1 %), notional {notional_usd6} USD6 under the cap {max_notional_usd6}",
@@ -528,7 +537,7 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
528
537
  limit_px=limit_sell,
529
538
  sz=ORDER_SIZE,
530
539
  tif=TimeInForce.IOC,
531
- cloid=2,
540
+ cloid=HyperCoreClientOrderId(2),
532
541
  reduce_only=True,
533
542
  ),
534
543
  override=None,
@@ -551,7 +560,7 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
551
560
  destination=HYPERCORE_VAULT,
552
561
  source_dex=XYZ_DEX,
553
562
  destination_dex=SPOT_DEX,
554
- token_index=0,
563
+ token_index=USDC_TOKEN_INDEX,
555
564
  amount_wei=from_dex,
556
565
  ),
557
566
  override=None,
@@ -586,7 +595,7 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
586
595
  destination=Web3.to_checksum_address(USDC_SYSTEM_ADDRESS),
587
596
  source_dex=SPOT_DEX,
588
597
  destination_dex=SPOT_DEX,
589
- token_index=0,
598
+ token_index=USDC_TOKEN_INDEX,
590
599
  amount_wei=to_evm,
591
600
  ),
592
601
  override=None,
@@ -95,7 +95,7 @@ from ipor_fusion.core import FusionFactory
95
95
  from ipor_fusion.core.fusion_factory import FusionInstance
96
96
  from ipor_fusion.fuses import ExternalStateOperationFuse
97
97
  from ipor_fusion.market_ids import IporFusionMarkets
98
- from ipor_fusion.types import Amount, ChainId, MarketId, Period, Shares
98
+ from ipor_fusion.types import Amount, ChainId, MarketId, Period, ProposalHash, Shares
99
99
 
100
100
  log = logging.getLogger("external_state_margin_leg_base")
101
101
 
@@ -288,7 +288,7 @@ RELEASE_OFFSET = REQUEST_OFFSET + RELEASE_DELAY
288
288
  DEMO_OFFSET = RELEASE_OFFSET + DEMO_DELAY
289
289
 
290
290
  # A hash that is deliberately not the pending proposal's, for the rejection demo.
291
- WRONG_PROPOSAL_HASH = b"\xde\xad" + b"\x00" * 30
291
+ WRONG_PROPOSAL_HASH = ProposalHash(b"\xde\xad" + b"\x00" * 30)
292
292
 
293
293
  # ── Derived from deployed signatures (NOT tunable) ───────────────────────────
294
294
  # Each of these is keccak over a signature the deployed contracts declare.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.0.0.dev30"
3
+ version = "4.0.0.dev35"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -318,16 +318,24 @@ from ipor_fusion.types import (
318
318
  Decimals,
319
319
  DeploymentRequestId,
320
320
  Fee,
321
+ HyperCoreActionId,
322
+ HyperCoreAsset,
323
+ HyperCoreClientOrderId,
324
+ HyperCoreOrderId,
325
+ HyperCoreTokenIndex,
321
326
  Liquidity,
322
327
  MappingStatus,
328
+ MarginTableId,
323
329
  MarketId,
324
330
  MessageId,
325
331
  MorphoBlueMarketId,
326
332
  NodeStatus,
327
333
  OperationId,
334
+ PayloadHash,
328
335
  Period,
329
336
  PositionSetHash,
330
337
  Price,
338
+ ProposalHash,
331
339
  ProposalId,
332
340
  ReturnRequestId,
333
341
  RoleId,
@@ -336,6 +344,8 @@ from ipor_fusion.types import (
336
344
  Tick,
337
345
  TokenId,
338
346
  TransferId,
347
+ TxHash,
348
+ parse_morpho_market_id,
339
349
  )
340
350
  from ipor_fusion.validation import (
341
351
  Erc20Holding,
@@ -605,6 +615,16 @@ __all__ = [
605
615
  "RoleId",
606
616
  "ChainId",
607
617
  "MorphoBlueMarketId",
618
+ "HyperCoreActionId",
619
+ "HyperCoreAsset",
620
+ "HyperCoreClientOrderId",
621
+ "HyperCoreOrderId",
622
+ "HyperCoreTokenIndex",
623
+ "MarginTableId",
624
+ "PayloadHash",
625
+ "ProposalHash",
626
+ "TxHash",
627
+ "parse_morpho_market_id",
608
628
  "AssetId",
609
629
  "CommandId",
610
630
  "DeploymentRequestId",
@@ -42,7 +42,7 @@ from ipor_fusion.readers.morpho import (
42
42
  MorphoReader,
43
43
  morpho_blue_address,
44
44
  )
45
- from ipor_fusion.types import ChainId, MorphoBlueMarketId
45
+ from ipor_fusion.types import ChainId, MorphoBlueMarketId, parse_morpho_market_id
46
46
  from ipor_fusion.vault_info import BLOCK_EXPLORER_URLS
47
47
 
48
48
 
@@ -54,12 +54,10 @@ class MarketIdType(click.ParamType):
54
54
  def convert(self, value, param, ctx): # type: ignore[override]
55
55
  if not isinstance(value, str):
56
56
  self.fail(f"expected string, got {type(value).__name__}", param, ctx)
57
- raw = value.strip().removeprefix("0x").removeprefix("0X")
58
- if len(raw) != 64 or not all(c in "0123456789abcdefABCDEF" for c in raw):
59
- self.fail(
60
- f"invalid Morpho market ID (expected 32-byte hex): {value}", param, ctx
61
- )
62
- return raw.lower()
57
+ try:
58
+ return parse_morpho_market_id(value)
59
+ except ValueError as exc:
60
+ self.fail(str(exc), param, ctx)
63
61
 
64
62
 
65
63
  MARKET_ID = MarketIdType()
@@ -106,7 +104,7 @@ def market() -> None:
106
104
  help="Emit machine-readable JSON instead of a table.",
107
105
  )
108
106
  def morpho_blue(
109
- market_id: str,
107
+ market_id: MorphoBlueMarketId,
110
108
  chain_id: ChainId,
111
109
  block: int | None,
112
110
  no_api: bool,
@@ -127,7 +125,7 @@ def morpho_blue(
127
125
  if block is not None:
128
126
  ctx.default_block = block
129
127
  reader = MorphoReader(ctx, morpho_blue_address(chain_id))
130
- mid = MorphoBlueMarketId(market_id)
128
+ mid = market_id
131
129
  params, state = reader.require_market(mid)
132
130
  rates = reader.rates_from(state, params)
133
131
 
@@ -171,7 +169,7 @@ def morpho_blue(
171
169
 
172
170
 
173
171
  def _print_market(
174
- market_id: str,
172
+ market_id: MorphoBlueMarketId,
175
173
  chain_id: ChainId,
176
174
  params: MorphoMarketParams,
177
175
  state: MorphoMarket,
@@ -181,11 +179,11 @@ def _print_market(
181
179
  chain_name = CHAIN_NAMES.get(chain_id, str(chain_id))
182
180
  explorer = BLOCK_EXPLORER_URLS.get(chain_id, "")
183
181
  liquidity = state.total_supply_assets - state.total_borrow_assets
184
- click.secho(f"Morpho Blue market 0x{market_id}", bold=True)
182
+ click.secho(f"Morpho Blue market {market_id}", bold=True)
185
183
  click.echo(f" Chain: {chain_name} (id {chain_id})")
186
184
  if explorer:
187
185
  click.echo(
188
- f" App: https://app.morpho.org/{chain_name}/market/0x{market_id}"
186
+ f" App: https://app.morpho.org/{chain_name}/market/{market_id}"
189
187
  )
190
188
  click.echo(f" Loan token: {params.loan_token}")
191
189
  click.echo(f" Collateral: {params.collateral_token}")
@@ -332,7 +330,7 @@ def _print_reallocate_hint(params: MorphoMarketParams) -> None:
332
330
  @click.option(
333
331
  "--market",
334
332
  "market_filter",
335
- type=str,
333
+ type=MARKET_ID,
336
334
  default=None,
337
335
  help="Filter caps/allocations to a single Morpho Blue market ID.",
338
336
  )
@@ -346,7 +344,7 @@ def _print_reallocate_hint(params: MorphoMarketParams) -> None:
346
344
  def meta_morpho(
347
345
  vault_address: ChecksumAddress,
348
346
  chain_id: ChainId,
349
- market_filter: str | None,
347
+ market_filter: MorphoBlueMarketId | None,
350
348
  json_output: bool,
351
349
  ) -> None:
352
350
  """Inspect a MetaMorpho V1 or Morpho Vault V2 by address.
@@ -361,22 +359,18 @@ def meta_morpho(
361
359
  except MorphoApiError as exc:
362
360
  raise click.UsageError(str(exc)) from exc
363
361
 
364
- market_filter_norm = (
365
- ("0x" + market_filter.removeprefix("0x").lower()) if market_filter else None
366
- )
367
-
368
362
  if json_output:
369
363
  click.echo(json_lib.dumps(build_meta_morpho_json(info, chain_id), indent=2))
370
364
  return
371
365
 
372
366
  if isinstance(info, VaultV2Info):
373
- _print_vault_v2(info, chain_id, market_filter_norm)
367
+ _print_vault_v2(info, chain_id, market_filter)
374
368
  else:
375
- _print_vault_v1(info, chain_id, market_filter_norm)
369
+ _print_vault_v1(info, chain_id, market_filter)
376
370
 
377
371
 
378
372
  def _print_vault_v2(
379
- vault: VaultV2Info, chain_id: ChainId, market_filter: str | None
373
+ vault: VaultV2Info, chain_id: ChainId, market_filter: MorphoBlueMarketId | None
380
374
  ) -> None:
381
375
  chain_name = CHAIN_NAMES.get(chain_id, str(chain_id))
382
376
  click.secho(f"Morpho Vault V2 — {vault.name} ({vault.symbol})", bold=True)
@@ -433,9 +427,7 @@ def _print_vault_v2(
433
427
  market_caps = [c for c in vault.caps if c.cap_type == "MarketV1"]
434
428
  other_caps = [c for c in vault.caps if c.cap_type != "MarketV1"]
435
429
  if market_filter:
436
- market_caps = [
437
- c for c in market_caps if (c.market_id or "").lower() == market_filter
438
- ]
430
+ market_caps = [c for c in market_caps if c.market_id == market_filter]
439
431
 
440
432
  click.secho(f"Morpho Blue market caps ({len(market_caps)}):", bold=True)
441
433
  _print_market_caps(market_caps, vault.asset_symbol, vault.asset_decimals)
@@ -508,7 +500,7 @@ def _print_other_caps(
508
500
 
509
501
 
510
502
  def _print_vault_v1(
511
- vault: VaultV1Info, chain_id: ChainId, market_filter: str | None
503
+ vault: VaultV1Info, chain_id: ChainId, market_filter: MorphoBlueMarketId | None
512
504
  ) -> None:
513
505
  chain_name = CHAIN_NAMES.get(chain_id, str(chain_id))
514
506
  public_allocator = PUBLIC_ALLOCATOR_ADDRESSES.get(chain_id)
@@ -552,7 +544,7 @@ def _print_vault_v1(
552
544
 
553
545
  allocations = vault.allocations
554
546
  if market_filter:
555
- allocations = [a for a in allocations if a.market_id.lower() == market_filter]
547
+ allocations = [a for a in allocations if a.market_id == market_filter]
556
548
  click.secho(f"Allocations ({len(allocations)}):", bold=True)
557
549
  if not allocations:
558
550
  click.echo(" (none)")
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  import logging
4
4
 
5
5
  from eth_account import Account
6
- from eth_typing import ChecksumAddress
6
+ from eth_typing import ChecksumAddress, HexStr
7
7
  from hexbytes import HexBytes
8
8
  from requests import ConnectionError as RequestsConnectionError
9
9
  from requests import HTTPError, Timeout
@@ -25,7 +25,7 @@ from ipor_fusion.core.logs import (
25
25
  get_logs_adaptive,
26
26
  )
27
27
  from ipor_fusion.errors import LogSourceUnavailable, TransactionError, get_revert_reason
28
- from ipor_fusion.types import ChainId
28
+ from ipor_fusion.types import ChainId, TxHash
29
29
 
30
30
  # web3 retries every allowlisted method on any HTTP error, a 400 included;
31
31
  # a too-wide eth_getLogs answered with HTTP 400/413 or a query timeout would be
@@ -229,7 +229,7 @@ class Web3Context:
229
229
  reason = get_revert_reason(self.web3, tx_hash, receipt)
230
230
  raise TransactionError(
231
231
  "Transaction failed",
232
- tx_hash=tx_hash.hex(),
232
+ tx_hash=TxHash(HexStr(tx_hash.to_0x_hex())),
233
233
  revert_reason=reason,
234
234
  )
235
235
  return receipt
@@ -32,7 +32,7 @@ from web3.types import BlockIdentifier, TxReceipt
32
32
  from ipor_fusion.core.context import Web3Context
33
33
  from ipor_fusion.core.contract import Call, ContractWrapper
34
34
  from ipor_fusion.market_ids import IporFusionMarkets
35
- from ipor_fusion.types import ZERO_ADDRESS, Amount, ChainId, MarketId
35
+ from ipor_fusion.types import ZERO_ADDRESS, Amount, ChainId, MarketId, ProposalHash
36
36
 
37
37
  if TYPE_CHECKING:
38
38
  from ipor_fusion.core.plasma_vault import PlasmaVault
@@ -79,12 +79,12 @@ class BalanceProposal:
79
79
  value: Amount
80
80
  nonce: int
81
81
  proposed_at: int
82
- proposal_hash: bytes
82
+ proposal_hash: ProposalHash
83
83
 
84
84
 
85
85
  def _hash_of(
86
86
  proposal: BalanceProposal, *, executor: ChecksumAddress, chain_id: ChainId
87
- ) -> bytes:
87
+ ) -> ProposalHash:
88
88
  """`proposal`'s canonical hash, as `confirmBalance` recomputes it.
89
89
 
90
90
  The sole mapping from a proposal's fields onto `proposal_hash` arguments,
@@ -132,7 +132,7 @@ class NavMark:
132
132
 
133
133
  proposed_at: int
134
134
  nonce: int
135
- proposal_hash: bytes
135
+ proposal_hash: ProposalHash
136
136
  propose_receipt: TxReceipt
137
137
  confirm_receipt: TxReceipt
138
138
  refresh_receipt: TxReceipt | None
@@ -463,7 +463,7 @@ class ExternalStateExecutor(ContractWrapper):
463
463
  value=Amount(value),
464
464
  nonce=nonce,
465
465
  proposed_at=proposed_at,
466
- proposal_hash=b"",
466
+ proposal_hash=ProposalHash(b""),
467
467
  )
468
468
  return replace(
469
469
  unstamped,
@@ -516,7 +516,7 @@ class ExternalStateExecutor(ContractWrapper):
516
516
  return self._write("proposeBalance(address,uint256)", balance_account, value)
517
517
 
518
518
  def confirm_balance(
519
- self, balance_account: ChecksumAddress, proposal_hash: bytes
519
+ self, balance_account: ChecksumAddress, proposal_hash: ProposalHash
520
520
  ) -> Call[None]:
521
521
  """CUSTODIAN-only: confirm the pending proposal for `balance_account`.
522
522
  Must be sent by a custodian other than the proposer, and `proposal_hash`
@@ -561,7 +561,7 @@ class ExternalStateExecutor(ContractWrapper):
561
561
  proposer: ChecksumAddress,
562
562
  proposed_at: int,
563
563
  nonce: int,
564
- ) -> bytes:
564
+ ) -> ProposalHash:
565
565
  """The confirm hash that `confirmBalance` verifies against:
566
566
  ``keccak(abi.encode(executor, chainId, balanceAccount, value, proposer,
567
567
  proposedAt, nonce))``.
@@ -571,26 +571,28 @@ class ExternalStateExecutor(ContractWrapper):
571
571
  event, never a fresh `nonce()` read -- see `nonce`. Pure -- no chain
572
572
  access -- so callers can pre-compute or verify a hash offline.
573
573
  """
574
- return keccak(
575
- encode(
576
- [
577
- "address",
578
- "uint256",
579
- "address",
580
- "uint256",
581
- "address",
582
- "uint64",
583
- "uint256",
584
- ],
585
- [
586
- Web3.to_checksum_address(executor),
587
- int(chain_id),
588
- Web3.to_checksum_address(balance_account),
589
- int(value),
590
- Web3.to_checksum_address(proposer),
591
- int(proposed_at),
592
- int(nonce),
593
- ],
574
+ return ProposalHash(
575
+ keccak(
576
+ encode(
577
+ [
578
+ "address",
579
+ "uint256",
580
+ "address",
581
+ "uint256",
582
+ "address",
583
+ "uint64",
584
+ "uint256",
585
+ ],
586
+ [
587
+ Web3.to_checksum_address(executor),
588
+ int(chain_id),
589
+ Web3.to_checksum_address(balance_account),
590
+ int(value),
591
+ Web3.to_checksum_address(proposer),
592
+ int(proposed_at),
593
+ int(nonce),
594
+ ],
595
+ )
594
596
  )
595
597
  )
596
598
 
@@ -11,6 +11,8 @@ from eth_utils import function_signature_to_4byte_selector
11
11
  from web3 import Web3
12
12
  from web3.types import TxReceipt
13
13
 
14
+ from ipor_fusion.types import TxHash
15
+
14
16
  log = logging.getLogger(__name__)
15
17
 
16
18
  PANIC_CODES: dict[int, str] = {
@@ -237,7 +239,7 @@ class TransactionError(IporFusionError):
237
239
  def __init__(
238
240
  self,
239
241
  message: str,
240
- tx_hash: str | None = None,
242
+ tx_hash: TxHash | None = None,
241
243
  revert_reason: str | None = None,
242
244
  ):
243
245
  self.tx_hash = tx_hash
@@ -10,10 +10,10 @@ import time
10
10
  from urllib.parse import urlencode
11
11
  from urllib.request import urlopen
12
12
 
13
- from eth_typing import HexAddress
13
+ from eth_typing import HexAddress, HexStr
14
14
 
15
15
  from ipor_fusion.cache import load_contract_cache, update_contract_cache
16
- from ipor_fusion.types import ChainId
16
+ from ipor_fusion.types import ChainId, TxHash
17
17
 
18
18
  ETHERSCAN_V2_URL = "https://api.etherscan.io/v2/api"
19
19
 
@@ -57,7 +57,7 @@ def get_contract_name(
57
57
 
58
58
  def get_deployment_tx(
59
59
  chain_id: ChainId, address: HexAddress, api_key: str | None = None
60
- ) -> tuple[str | None, str | None]:
60
+ ) -> tuple[TxHash | None, str | None]:
61
61
  """Return ``(tx_hash, error)`` for a contract deployment.
62
62
 
63
63
  ``error`` is a short machine-readable code when ``tx_hash`` is None and the
@@ -69,7 +69,7 @@ def get_deployment_tx(
69
69
 
70
70
  def _fetch_contract_creation_tx(
71
71
  chain_id: ChainId, address: HexAddress, api_key: str | None = None
72
- ) -> tuple[str | None, str | None]:
72
+ ) -> tuple[TxHash | None, str | None]:
73
73
  if chain_id not in SUPPORTED_CHAINS:
74
74
  return None, "chain-not-supported"
75
75
  if not api_key:
@@ -91,7 +91,8 @@ def _fetch_contract_creation_tx(
91
91
  with urlopen(url, timeout=10) as resp: # noqa: S310
92
92
  data = json.loads(resp.read().decode())
93
93
  if data.get("status") == "1" and data.get("result"):
94
- return data["result"][0].get("txHash"), None # type: ignore[no-any-return]
94
+ tx_hash = data["result"][0].get("txHash")
95
+ return (TxHash(HexStr(tx_hash)) if tx_hash else None), None
95
96
  result_text = str(data.get("result", "")).lower()
96
97
  if "free api access is not supported" in result_text:
97
98
  return None, "etherscan-paid-tier-required"
@@ -28,10 +28,12 @@ from typing import Any
28
28
 
29
29
  from eth_abi import decode
30
30
  from eth_abi.exceptions import DecodingError
31
- from eth_typing import ChecksumAddress
31
+ from eth_typing import ChecksumAddress, HexStr
32
32
  from web3 import Web3
33
33
  from web3.types import TxReceipt
34
34
 
35
+ from ipor_fusion.types import TxHash
36
+
35
37
 
36
38
  @dataclass(frozen=True, slots=True)
37
39
  class ExternalStateEventSpec:
@@ -134,7 +136,7 @@ class ExternalStateEvent:
134
136
  emitter: ChecksumAddress
135
137
  args: dict[str, Any]
136
138
  block_number: int | None = None
137
- transaction_hash: str | None = None
139
+ transaction_hash: TxHash | None = None
138
140
  log_index: int | None = None
139
141
 
140
142
 
@@ -191,10 +193,10 @@ def external_state_event_name(topic: bytes | str) -> str | None:
191
193
  return spec.name if spec else None
192
194
 
193
195
 
194
- def _hex(value: Any) -> str | None:
196
+ def _hex(value: Any) -> TxHash | None:
195
197
  if value is None:
196
198
  return None
197
- return "0x" + _as_bytes(value, "transactionHash").hex()
199
+ return TxHash(HexStr("0x" + _as_bytes(value, "transactionHash").hex()))
198
200
 
199
201
 
200
202
  def decode_external_state_event(log: Mapping[str, Any]) -> ExternalStateEvent | None: