ipor-fusion 4.0.0.dev156__tar.gz → 4.0.0.dev159__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 (303) hide show
  1. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/MIGRATION_4.md +19 -0
  2. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/PKG-INFO +1 -1
  3. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/pyproject.toml +1 -1
  4. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/__init__.py +82 -0
  5. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/oracle_mapping_view.py +9 -5
  6. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/external_state_executor.py +15 -7
  7. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/__init__.py +36 -0
  8. ipor_fusion-4.0.0.dev159/src/ipor_fusion/fuses/events.py +45 -0
  9. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/external_state_events.py +93 -8
  10. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/hypercore_events.py +185 -10
  11. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/mcp/models.py +3 -1
  12. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/__init__.py +26 -0
  13. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/oracle_mapping_nodes.py +158 -10
  14. ipor_fusion-4.0.0.dev159/tests/_event_args.py +29 -0
  15. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_oracle_mapping.py +13 -5
  16. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_external_state_events.py +23 -0
  17. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_external_state_executor.py +12 -0
  18. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_hypercore_events.py +20 -7
  19. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_mcp_models.py +15 -3
  20. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_oracle_mapping.py +59 -43
  21. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_public_api.py +69 -0
  22. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/typed_client/consumer.py +28 -0
  23. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/typed_client/rejected.py +7 -0
  24. ipor_fusion-4.0.0.dev156/src/ipor_fusion/fuses/events.py +0 -25
  25. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.claude-plugin/marketplace.json +0 -0
  26. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.claude-plugin/plugin.json +0 -0
  27. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.env.example +0 -0
  28. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.gemini/settings.json +0 -0
  29. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.git-blame-ignore-revs +0 -0
  30. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.github/workflows/cd.yml +0 -0
  31. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.github/workflows/ci.yml +0 -0
  32. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.github/workflows/commit-lint.yml +0 -0
  33. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.github/workflows/notify-slack.yml +0 -0
  34. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.github/workflows/python-build.yml +0 -0
  35. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.github/workflows/python-publish.yml +0 -0
  36. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.github/workflows/release.yml +0 -0
  37. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.github/workflows/report-slack.yml +0 -0
  38. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.gitignore +0 -0
  39. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.mcp.json +0 -0
  40. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.pre-commit-config.yaml +0 -0
  41. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/.python-version +0 -0
  42. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/AGENTS.md +0 -0
  43. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/CHANGELOG.md +0 -0
  44. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/CLAUDE.md +0 -0
  45. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/CODEOWNERS +0 -0
  46. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/LICENSE +0 -0
  47. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/README.md +0 -0
  48. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/build.sh +0 -0
  49. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/examples/CONTRIBUTING.md +0 -0
  50. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/examples/README.md +0 -0
  51. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  52. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  53. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  54. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  55. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/examples/external_state_margin_leg_base.py +0 -0
  56. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/examples/simple_aave_v3_supply_base.py +0 -0
  57. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/pytest.ini +0 -0
  58. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/scripts/commit-check.sh +0 -0
  59. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/scripts/crosschain_readiness.py +0 -0
  60. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/skills/ipor-deploy-vault/SKILL.md +0 -0
  61. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/about.py +0 -0
  62. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cache.py +0 -0
  63. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/chains.py +0 -0
  64. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/__init__.py +0 -0
  65. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  66. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/config_cmd.py +0 -0
  67. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/config_store.py +0 -0
  68. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/main.py +0 -0
  69. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/market_cmd.py +0 -0
  70. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/options.py +0 -0
  71. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  72. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/vault_health.py +0 -0
  73. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  74. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  75. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  76. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/config/__init__.py +0 -0
  77. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/config/roles.py +0 -0
  78. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/__init__.py +0 -0
  79. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/access.py +0 -0
  80. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/address.py +0 -0
  81. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/context.py +0 -0
  82. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/contract.py +0 -0
  83. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/erc20.py +0 -0
  84. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/fee_manager.py +0 -0
  85. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/fuse.py +0 -0
  86. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/fuse_action.py +0 -0
  87. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/fusion_factory.py +0 -0
  88. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/logs.py +0 -0
  89. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/multicall.py +0 -0
  90. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/oracle.py +0 -0
  91. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/plasma_vault.py +0 -0
  92. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/rewards_manager.py +0 -0
  93. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/simulation.py +0 -0
  94. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  95. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/__init__.py +0 -0
  96. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  97. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  98. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  99. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  100. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  101. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  102. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  103. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  104. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  105. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/contracts.py +0 -0
  106. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/discovery.py +0 -0
  107. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/errors.py +0 -0
  108. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  109. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  110. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  111. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  112. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/lane.py +0 -0
  113. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/logs.py +0 -0
  114. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/messages.py +0 -0
  115. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/simulation.py +0 -0
  116. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  117. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  118. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  119. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  120. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  121. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/crosschain/transport.py +0 -0
  122. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/dependency_graph.py +0 -0
  123. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/entry_cli.py +0 -0
  124. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/entry_mcp.py +0 -0
  125. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/errors.py +0 -0
  126. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/explorer.py +0 -0
  127. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/field_docs.py +0 -0
  128. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  129. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/async_action.py +0 -0
  130. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/base.py +0 -0
  131. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  132. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/erc4626.py +0 -0
  133. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  134. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/external_state.py +0 -0
  135. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  136. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  137. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/hypercore.py +0 -0
  138. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/merkl.py +0 -0
  139. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/morpho.py +0 -0
  140. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  141. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  142. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/fuses/universal.py +0 -0
  143. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/guide/__init__.py +0 -0
  144. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/guide/architecture.md +0 -0
  145. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/guide/glossary.md +0 -0
  146. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/guide/invariants.md +0 -0
  147. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/guide/quickstart.md +0 -0
  148. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/market_ids.py +0 -0
  149. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/market_info.py +0 -0
  150. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/mcp/__init__.py +0 -0
  151. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/mcp/guide.py +0 -0
  152. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/mcp/server.py +0 -0
  153. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/morpho_api.py +0 -0
  154. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/py.typed +0 -0
  155. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/aave_v3.py +0 -0
  156. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/aave_v4.py +0 -0
  157. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/compound_v3.py +0 -0
  158. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/hypercore.py +0 -0
  159. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  160. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/lending_health.py +0 -0
  161. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/morpho.py +0 -0
  162. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  163. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  164. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/position_manager.py +0 -0
  165. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  166. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  167. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/readers/unpriceable.py +0 -0
  168. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/substrates.py +0 -0
  169. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/types.py +0 -0
  170. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/validation.py +0 -0
  171. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/vault_data.py +0 -0
  172. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/vault_erc20.py +0 -0
  173. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/vault_info.py +0 -0
  174. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/vault_managers.py +0 -0
  175. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/vault_positions.py +0 -0
  176. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/src/ipor_fusion/vault_reads.py +0 -0
  177. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/UniswapV3UniversalRouter.py +0 -0
  178. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_crosschain.py +0 -0
  179. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_crosschain_lifecycle.py +0 -0
  180. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_crosschain_recovery.py +0 -0
  181. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_euler_v2.py +0 -0
  182. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_foundry.py +0 -0
  183. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_guide.py +0 -0
  184. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_hypercore_model.py +0 -0
  185. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_hypercore_shadow.py +0 -0
  186. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_multicall.py +0 -0
  187. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_simulate.py +0 -0
  188. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/_validation.py +0 -0
  189. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/addresses.py +0 -0
  190. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/conftest.py +0 -0
  191. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/constants.py +0 -0
  192. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  193. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/fixtures/hypercore_market55.json +0 -0
  194. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/fixtures/vault_info_golden/clean.json +0 -0
  195. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  196. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/fixtures/vault_info_golden/rich.json +0 -0
  197. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  198. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_about.py +0 -0
  199. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_access_manager.py +0 -0
  200. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cache.py +0 -0
  201. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_chains.py +0 -0
  202. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_changelog.py +0 -0
  203. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_commands.py +0 -0
  204. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_config_store.py +0 -0
  205. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_helpers.py +0 -0
  206. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_hypercore.py +0 -0
  207. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_lending_health.py +0 -0
  208. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_market_morpho_blue.py +0 -0
  209. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_pending_requests_scan.py +0 -0
  210. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_role_accounts.py +0 -0
  211. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_vault_info_golden.py +0 -0
  212. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_vault_predates_getters.py +0 -0
  213. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_cli_vault_validate.py +0 -0
  214. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_contract_call.py +0 -0
  215. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_contract_encoder.py +0 -0
  216. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_ccip_events.py +0 -0
  217. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_ccip_indexer.py +0 -0
  218. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_ccip_quote.py +0 -0
  219. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_chainlink.py +0 -0
  220. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_contracts.py +0 -0
  221. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_encoding.py +0 -0
  222. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_errors.py +0 -0
  223. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_lane.py +0 -0
  224. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_layering.py +0 -0
  225. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_readiness.py +0 -0
  226. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_readiness_report.py +0 -0
  227. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_crosschain_transport.py +0 -0
  228. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_docs_typing.py +0 -0
  229. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_erc20.py +0 -0
  230. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_error_hierarchy.py +0 -0
  231. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_examples_composed_hypercore.py +0 -0
  232. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_examples_crosschain.py +0 -0
  233. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  234. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_examples_vaults.py +0 -0
  235. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_explorer.py +0 -0
  236. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_fee_manager.py +0 -0
  237. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_fuse_encoding.py +0 -0
  238. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_fusion_instance.py +0 -0
  239. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_guide.py +0 -0
  240. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_hypercore_deployment.py +0 -0
  241. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_hypercore_flow.py +0 -0
  242. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_hypercore_live.py +0 -0
  243. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_hypercore_outcome.py +0 -0
  244. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_hypercore_readers.py +0 -0
  245. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_hypercore_simulation.py +0 -0
  246. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_logs.py +0 -0
  247. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_mcp_hypercore.py +0 -0
  248. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_mcp_server.py +0 -0
  249. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_mcp_vault_validate.py +0 -0
  250. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_multicall.py +0 -0
  251. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_oracle.py +0 -0
  252. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_plasma_vault.py +0 -0
  253. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_public_type_reachability.py +0 -0
  254. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_reader_encoding.py +0 -0
  255. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_readiness_selection.py +0 -0
  256. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_revert_decoding.py +0 -0
  257. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_rewards_manager.py +0 -0
  258. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_roles.py +0 -0
  259. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_sdk_layering.py +0 -0
  260. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  261. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  262. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  263. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_crosschain_canary.py +0 -0
  264. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_crosschain_hypercore.py +0 -0
  265. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  266. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  267. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  268. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  269. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  270. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  271. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  272. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_examples_arbitrum.py +0 -0
  273. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_examples_base.py +0 -0
  274. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_examples_crosschain.py +0 -0
  275. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_external_state_executor_base.py +0 -0
  276. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  277. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  278. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  279. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_morpho_blue.py +0 -0
  280. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_pilot_v3.py +0 -0
  281. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  282. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  283. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  284. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  285. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_readers_integration.py +0 -0
  286. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_release_funds.py +0 -0
  287. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_swap_on_base.py +0 -0
  288. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  289. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_simulation_observation.py +0 -0
  290. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_solidity_compiler.py +0 -0
  291. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_solidity_mirrors.py +0 -0
  292. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_substrates.py +0 -0
  293. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_types_and_events.py +0 -0
  294. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_unpriceable_tokens.py +0 -0
  295. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_validation.py +0 -0
  296. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_vault_data_block.py +0 -0
  297. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_vault_dep_graph.py +0 -0
  298. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_vault_info_onchain_base.py +0 -0
  299. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  300. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_vault_simulator_blocks.py +0 -0
  301. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_web3_context.py +0 -0
  302. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/tests/test_withdraw_manager.py +0 -0
  303. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev159}/uv.lock +0 -0
@@ -787,6 +787,7 @@ untyped code needs none of this section.
787
787
  | `build_morpho_blue_market_json` | `MorphoBlueMarketJson` |
788
788
  | `build_meta_morpho_json` | `MetaMorphoV1Json \| MetaMorphoV2Json`, told apart by `doc["version"]` |
789
789
  | `RoleAccount.to_dict` | `RoleAccountJson` |
790
+ | `OracleMapping.to_dict` / `OracleNode.to_dict` | `OracleMappingJson` / `OracleNodeJson` |
790
791
 
791
792
  Every nested block has its own TypedDict (`FeesJson`, `WithdrawManagerJson`,
792
793
  `BalanceFuseJson`, `ReconciliationJson`, `HyperCoreJson`, `MorphoSupplyingVaultJson`,
@@ -813,6 +814,24 @@ that only some entries carry is `NotRequired` (a balance fuse's `pct_of_total` a
813
814
  age) or `DeploymentErrorJson` (`{"error": ...}`) or `None`; `share_price` is
814
815
  `SharePriceJson` (`asset`, and `usd` when the asset is priced); `dependency_graph`
815
816
  is `DependencyGraphJson` (`edges`, `update_reach`, `update_groups`).
817
+ - `OracleNode.source_detail` is `SourceDetailJson`, one TypedDict per feed kind
818
+ (`ChainlinkDetailJson`, `DualXrefDetailJson`, `Erc4626DetailJson`,
819
+ `MorphoFeedDetailJson`, `MiddlewareFallbackDetailJson`; importable from
820
+ `ipor_fusion` and `ipor_fusion.readers`). Narrow by a key before reading a
821
+ kind-specific one: `if detail is not None and "aggregator" in detail:
822
+ detail["description"]`.
823
+ - Event `args` are typed per event kind: `ExternalStateEvent.args` is
824
+ `ExternalStateEventArgs` and `HyperCoreEvent.args` is `HyperCoreEventArgs`, a union
825
+ of one TypedDict per event (`ExternalStateUnpausedArgs`,
826
+ `HyperCoreDepositFuseEnterArgs`, ...; `EXTERNAL_STATE_EVENT_ARGS` /
827
+ `HYPERCORE_EVENT_ARGS` map an event name to its shape). Values carry nominal types
828
+ (`Amount`, `MarketId`, `FuseAddress`, `HyperCoreTokenIndex`, `PayloadHash`, web3's
829
+ `Timestamp`, ...). `event.args["signer"]` no longer type-checks on its own: narrow
830
+ with a key test (`if "signer" in event.args:`). `HyperCoreEvent.fuse` is a
831
+ `FuseAddress | None`.
832
+ - `RawLog` (the log shape `ExternalStateExecutor.parse_balance_proposed` /
833
+ `find_balance_proposed` accept) is `Mapping[str, object]`, not `Mapping[str, Any]`;
834
+ a web3 `LogReceipt` still fits it.
816
835
 
817
836
  ## Behavior changes
818
837
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev156
3
+ Version: 4.0.0.dev159
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.0.0.dev156"
3
+ version = "4.0.0.dev159"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -314,15 +314,44 @@ from ipor_fusion.fuses import (
314
314
  system_address,
315
315
  )
316
316
  from ipor_fusion.fuses.external_state_events import (
317
+ EXTERNAL_STATE_EVENT_ARGS,
317
318
  EXTERNAL_STATE_EVENT_SPECS,
318
319
  EXTERNAL_STATE_EVENTS,
319
320
  EXTERNAL_STATE_TOPICS,
321
+ ExternalStateAssetRescuedArgs,
322
+ ExternalStateBigChangeDetectedArgs,
323
+ ExternalStateCustodianTimestampUpdatedArgs,
320
324
  ExternalStateEvent,
325
+ ExternalStateEventArgs,
321
326
  ExternalStateEventSpec,
327
+ ExternalStateExecutorArgs,
328
+ ExternalStateOperationArgs,
329
+ ExternalStateTotalBalanceUpdatedArgs,
330
+ ExternalStateUnpausedArgs,
322
331
  decode_external_state_event,
323
332
  external_state_event_name,
324
333
  external_state_events,
325
334
  )
335
+ from ipor_fusion.fuses.hypercore_events import (
336
+ HYPERCORE_EVENT_ARGS,
337
+ HyperCoreActionEnqueuedArgs,
338
+ HyperCoreActionSettledArgs,
339
+ HyperCoreBuilderFeeFuseEnterArgs,
340
+ HyperCoreCancelByCloidArgs,
341
+ HyperCoreCancelByOidArgs,
342
+ HyperCoreDepositFuseEnterArgs,
343
+ HyperCoreEventArgs,
344
+ HyperCoreMarginFuseEnterArgs,
345
+ HyperCoreObserverSetChangedArgs,
346
+ HyperCoreObserverSetProposedArgs,
347
+ HyperCoreOrderFuseEnterArgs,
348
+ HyperCoreRecoveryExecutedArgs,
349
+ HyperCoreRecoveryProposedArgs,
350
+ HyperCoreReportedActionSettledArgs,
351
+ HyperCoreReportSubmittedArgs,
352
+ HyperCoreSendFuseSendAssetArgs,
353
+ HyperCoreSendFuseSpotSendArgs,
354
+ )
326
355
  from ipor_fusion.market_ids import IporFusionMarkets
327
356
  from ipor_fusion.market_info import (
328
357
  MetaMorphoAdapterJson,
@@ -422,6 +451,20 @@ from ipor_fusion.readers import (
422
451
  read_hypercore_transfer_snapshot,
423
452
  read_hypercore_vault_state,
424
453
  )
454
+ from ipor_fusion.readers.oracle_mapping_nodes import (
455
+ AggregatorDetailJson,
456
+ AggregatorFeedDetailJson,
457
+ ChainlinkDetailJson,
458
+ DualXrefDetailJson,
459
+ Erc4626DetailJson,
460
+ MiddlewareFallbackDetailJson,
461
+ MorphoFeedDetailJson,
462
+ OracleAssetJson,
463
+ OracleMappingJson,
464
+ OracleNodeJson,
465
+ OraclePriceJson,
466
+ SourceDetailJson,
467
+ )
425
468
  from ipor_fusion.substrates import (
426
469
  SubstrateInfo,
427
470
  decode_substrate,
@@ -546,6 +589,15 @@ __all__ = [
546
589
  "EXTERNAL_STATE_EVENTS",
547
590
  "EXTERNAL_STATE_TOPICS",
548
591
  "ExternalStateEvent",
592
+ "EXTERNAL_STATE_EVENT_ARGS",
593
+ "ExternalStateAssetRescuedArgs",
594
+ "ExternalStateBigChangeDetectedArgs",
595
+ "ExternalStateCustodianTimestampUpdatedArgs",
596
+ "ExternalStateEventArgs",
597
+ "ExternalStateExecutorArgs",
598
+ "ExternalStateOperationArgs",
599
+ "ExternalStateTotalBalanceUpdatedArgs",
600
+ "ExternalStateUnpausedArgs",
549
601
  "ExternalStateEventDecodeError",
550
602
  "ExternalStateEventSpec",
551
603
  "decode_external_state_event",
@@ -554,6 +606,24 @@ __all__ = [
554
606
  "HYPERCORE_EVENTS",
555
607
  "HYPERCORE_EVENT_SPECS",
556
608
  "HyperCoreEvent",
609
+ "HYPERCORE_EVENT_ARGS",
610
+ "HyperCoreActionEnqueuedArgs",
611
+ "HyperCoreActionSettledArgs",
612
+ "HyperCoreBuilderFeeFuseEnterArgs",
613
+ "HyperCoreCancelByCloidArgs",
614
+ "HyperCoreCancelByOidArgs",
615
+ "HyperCoreDepositFuseEnterArgs",
616
+ "HyperCoreEventArgs",
617
+ "HyperCoreMarginFuseEnterArgs",
618
+ "HyperCoreObserverSetChangedArgs",
619
+ "HyperCoreObserverSetProposedArgs",
620
+ "HyperCoreOrderFuseEnterArgs",
621
+ "HyperCoreRecoveryExecutedArgs",
622
+ "HyperCoreRecoveryProposedArgs",
623
+ "HyperCoreReportSubmittedArgs",
624
+ "HyperCoreReportedActionSettledArgs",
625
+ "HyperCoreSendFuseSendAssetArgs",
626
+ "HyperCoreSendFuseSpotSendArgs",
557
627
  "HyperCoreEventSpec",
558
628
  "decode_hypercore_event",
559
629
  "find_hypercore_events",
@@ -945,6 +1015,18 @@ __all__ = [
945
1015
  "OracleAsset",
946
1016
  "OracleMapping",
947
1017
  "OracleNode",
1018
+ "AggregatorDetailJson",
1019
+ "AggregatorFeedDetailJson",
1020
+ "ChainlinkDetailJson",
1021
+ "DualXrefDetailJson",
1022
+ "Erc4626DetailJson",
1023
+ "MiddlewareFallbackDetailJson",
1024
+ "MorphoFeedDetailJson",
1025
+ "OracleAssetJson",
1026
+ "OracleMappingJson",
1027
+ "OracleNodeJson",
1028
+ "OraclePriceJson",
1029
+ "SourceDetailJson",
948
1030
  "OraclePrice",
949
1031
  "build_oracle_mapping",
950
1032
  "OracleMappingReader",
@@ -24,21 +24,25 @@ def _format_wad_price(price: OraclePrice | None) -> str:
24
24
 
25
25
  def _print_feed_line(node: OracleNode) -> None:
26
26
  """The feed's self-declared units — key for confirming what a value means."""
27
- detail = node.source_detail or {}
27
+ detail = node.source_detail
28
28
  if node.source_type in (TYPE_CHAINLINK, TYPE_CHAINLINK_STYLE):
29
- if detail.get("description"):
29
+ if detail is not None and "aggregator" in detail and detail["description"]:
30
30
  click.echo(f" Feed: {detail['description']}")
31
31
  else:
32
32
  # only chainlink_style can land here — the confirmed tier
33
33
  # requires a non-empty description
34
34
  click.secho(" Feed: (no description)", fg="yellow")
35
- elif node.source_type == TYPE_DUAL_XREF:
35
+ elif (
36
+ node.source_type == TYPE_DUAL_XREF
37
+ and detail is not None
38
+ and "asset_x" in detail
39
+ ):
36
40
  rendered = [
37
41
  # quoted — the descriptions themselves contain " / "
38
42
  f'"{d}"' if d else click.style("(no description)", fg="yellow")
39
43
  for d in (
40
- (detail.get(key) or {}).get("description")
41
- for key in ("asset_x_asset_y_feed", "asset_y_usd_feed")
44
+ detail["asset_x_asset_y_feed"]["description"],
45
+ detail["asset_y_usd_feed"]["description"],
42
46
  )
43
47
  ]
44
48
  click.echo(f" Feed: {' × '.join(rendered)}")
@@ -18,7 +18,7 @@ from __future__ import annotations
18
18
 
19
19
  from collections.abc import Iterable, Mapping
20
20
  from dataclasses import dataclass, replace
21
- from typing import Any
21
+ from typing import TypeAlias
22
22
 
23
23
  from eth_abi import decode, encode
24
24
  from eth_abi.exceptions import DecodingError
@@ -44,8 +44,9 @@ from ipor_fusion.types import (
44
44
  # (HexBytes fields, checksummed address), and a raw JSON-RPC or
45
45
  # `eth_simulateV1` row (0x-hex strings, lowercase address). Looser than
46
46
  # `web3.types.LogReceipt`, which the rest of `core/` uses, because those rows
47
- # carry neither its field types nor all of its required keys.
48
- RawLog = Mapping[str, Any]
47
+ # carry neither its field types nor all of its required keys. Every field is
48
+ # read as `object` and narrowed; a `LogReceipt` is one of these mappings.
49
+ RawLog: TypeAlias = Mapping[str, object]
49
50
 
50
51
 
51
52
  def _log_emitter(log: RawLog) -> ChecksumAddress | None:
@@ -55,7 +56,7 @@ def _log_emitter(log: RawLog) -> ChecksumAddress | None:
55
56
  matched against an expected emitter, and a caller scanning foreign rows
56
57
  should skip such a log rather than have the scan abort on it."""
57
58
  emitter = log.get("address")
58
- if emitter is None:
59
+ if not isinstance(emitter, str | bytes):
59
60
  return None
60
61
  try:
61
62
  return Web3.to_checksum_address(emitter)
@@ -590,11 +591,14 @@ class ExternalStateExecutor(ContractWrapper):
590
591
  event -- the rule `_log_emitter` already applies to an unreadable
591
592
  address, and it keeps a raise meaning "ours, but the payload is broken".
592
593
  """
593
- topics = log.get("topics") or ()
594
- if not topics:
594
+ topics = log.get("topics")
595
+ if not isinstance(topics, list | tuple) or not topics:
596
+ return False
597
+ topic = topics[0]
598
+ if not isinstance(topic, str | bytes | bytearray):
595
599
  return False
596
600
  try:
597
- return HexBytes(topics[0]) == cls._BALANCE_PROPOSED_TOPIC
601
+ return HexBytes(topic) == cls._BALANCE_PROPOSED_TOPIC
598
602
  except (ValueError, TypeError):
599
603
  return False
600
604
 
@@ -652,6 +656,10 @@ class ExternalStateExecutor(ContractWrapper):
652
656
  data = log.get("data")
653
657
  if data is None:
654
658
  raise ExternalStateError("BalanceProposed log carries no data")
659
+ if not isinstance(data, str | bytes | bytearray):
660
+ raise ExternalStateError(
661
+ f"malformed BalanceProposed data: {type(data).__name__}"
662
+ )
655
663
  try:
656
664
  # Unpacked in the order `BalanceProposed` declares them; all six
657
665
  # are unindexed, so topics carries topic0 alone.
@@ -50,10 +50,28 @@ from ipor_fusion.fuses.hypercore import (
50
50
  system_address,
51
51
  )
52
52
  from ipor_fusion.fuses.hypercore_events import (
53
+ HYPERCORE_EVENT_ARGS,
53
54
  HYPERCORE_EVENT_SPECS,
54
55
  HYPERCORE_EVENTS,
56
+ HyperCoreActionEnqueuedArgs,
57
+ HyperCoreActionSettledArgs,
58
+ HyperCoreBuilderFeeFuseEnterArgs,
59
+ HyperCoreCancelByCloidArgs,
60
+ HyperCoreCancelByOidArgs,
61
+ HyperCoreDepositFuseEnterArgs,
55
62
  HyperCoreEvent,
63
+ HyperCoreEventArgs,
56
64
  HyperCoreEventSpec,
65
+ HyperCoreMarginFuseEnterArgs,
66
+ HyperCoreObserverSetChangedArgs,
67
+ HyperCoreObserverSetProposedArgs,
68
+ HyperCoreOrderFuseEnterArgs,
69
+ HyperCoreRecoveryExecutedArgs,
70
+ HyperCoreRecoveryProposedArgs,
71
+ HyperCoreReportedActionSettledArgs,
72
+ HyperCoreReportSubmittedArgs,
73
+ HyperCoreSendFuseSendAssetArgs,
74
+ HyperCoreSendFuseSpotSendArgs,
57
75
  decode_hypercore_event,
58
76
  find_hypercore_events,
59
77
  hypercore_event_name,
@@ -94,6 +112,24 @@ __all__ = [
94
112
  "HYPERCORE_EVENTS",
95
113
  "HYPERCORE_EVENT_SPECS",
96
114
  "HyperCoreEvent",
115
+ "HYPERCORE_EVENT_ARGS",
116
+ "HyperCoreActionEnqueuedArgs",
117
+ "HyperCoreActionSettledArgs",
118
+ "HyperCoreBuilderFeeFuseEnterArgs",
119
+ "HyperCoreCancelByCloidArgs",
120
+ "HyperCoreCancelByOidArgs",
121
+ "HyperCoreDepositFuseEnterArgs",
122
+ "HyperCoreEventArgs",
123
+ "HyperCoreMarginFuseEnterArgs",
124
+ "HyperCoreObserverSetChangedArgs",
125
+ "HyperCoreObserverSetProposedArgs",
126
+ "HyperCoreOrderFuseEnterArgs",
127
+ "HyperCoreRecoveryExecutedArgs",
128
+ "HyperCoreRecoveryProposedArgs",
129
+ "HyperCoreReportSubmittedArgs",
130
+ "HyperCoreReportedActionSettledArgs",
131
+ "HyperCoreSendFuseSendAssetArgs",
132
+ "HyperCoreSendFuseSpotSendArgs",
97
133
  "HyperCoreEventSpec",
98
134
  "decode_hypercore_event",
99
135
  "find_hypercore_events",
@@ -0,0 +1,45 @@
1
+ from eth_abi import decode
2
+ from eth_typing import ChecksumAddress
3
+ from web3 import Web3
4
+ from web3.types import TxReceipt
5
+
6
+
7
+ def extract_events(
8
+ receipt: TxReceipt,
9
+ event_signature: str,
10
+ abi_types: list[str],
11
+ dataclass_type,
12
+ ):
13
+ sig_hash = Web3.keccak(text=event_signature)
14
+ events = []
15
+ for log in receipt["logs"]:
16
+ if log["topics"][0] == sig_hash:
17
+ decoded = decode(abi_types, log["data"])
18
+ events.append(
19
+ dataclass_type(
20
+ *(
21
+ Web3.to_checksum_address(value) if abi == "address" else value
22
+ for abi, value in zip(abi_types, decoded, strict=True)
23
+ )
24
+ )
25
+ )
26
+ return events
27
+
28
+
29
+ def abi_value(abi_type: str, value: object) -> int | bool | bytes | ChecksumAddress:
30
+ """One ``eth_abi``-decoded event parameter as the Python type its ABI type
31
+ decodes to: an address checksummed, a ``uintN`` / ``intN`` an int, a
32
+ ``bool`` a bool, a ``bytesN`` bytes. Anything else raises ``TypeError``."""
33
+ if abi_type == "address" and isinstance(value, str):
34
+ return Web3.to_checksum_address(value)
35
+ if abi_type == "bool" and isinstance(value, bool):
36
+ return value
37
+ if (
38
+ abi_type.startswith(("uint", "int"))
39
+ and isinstance(value, int)
40
+ and not isinstance(value, bool)
41
+ ):
42
+ return value
43
+ if abi_type.startswith("bytes") and isinstance(value, bytes):
44
+ return value
45
+ raise TypeError(f"{abi_type} decoded as {type(value).__name__}")
@@ -24,16 +24,17 @@ from __future__ import annotations
24
24
 
25
25
  from collections.abc import Mapping
26
26
  from dataclasses import dataclass
27
- from typing import Any
27
+ from typing import TypeAlias, TypedDict, cast
28
28
 
29
29
  from eth_abi import decode
30
30
  from eth_abi.exceptions import DecodingError
31
31
  from eth_typing import ChecksumAddress
32
32
  from web3 import Web3
33
- from web3.types import TxReceipt
33
+ from web3.types import Timestamp, TxReceipt
34
34
 
35
35
  from ipor_fusion.errors import ExternalStateEventDecodeError
36
- from ipor_fusion.types import TxHash, parse_tx_hash
36
+ from ipor_fusion.fuses.events import abi_value
37
+ from ipor_fusion.types import Amount, FuseAddress, MarketId, TxHash, parse_tx_hash
37
38
 
38
39
 
39
40
  @dataclass(frozen=True, slots=True)
@@ -114,6 +115,85 @@ EXTERNAL_STATE_EVENT_SPECS: tuple[ExternalStateEventSpec, ...] = (
114
115
  ),
115
116
  )
116
117
 
118
+
119
+ class ExternalStateBigChangeDetectedArgs(TypedDict):
120
+ previousTotal: Amount
121
+ newTotal: Amount
122
+ thresholdBps: int
123
+
124
+
125
+ class ExternalStateCustodianTimestampUpdatedArgs(TypedDict):
126
+ """``ExternalStateBalanceFuseLastCustodianTimestampUpdated``."""
127
+
128
+ oldTimestamp: Timestamp
129
+ newTimestamp: Timestamp
130
+
131
+
132
+ class ExternalStateTotalBalanceUpdatedArgs(TypedDict):
133
+ """``ExternalStateBalanceFuseLastTotalBalanceUpdated``."""
134
+
135
+ oldTotalBalance: Amount
136
+ newTotalBalance: Amount
137
+
138
+
139
+ class ExternalStateUnpausedArgs(TypedDict):
140
+ signer: ChecksumAddress
141
+ confirmedTotalBalance: Amount
142
+ nonce: int
143
+
144
+
145
+ class ExternalStateAssetRescuedArgs(TypedDict):
146
+ asset: ChecksumAddress
147
+
148
+
149
+ class ExternalStateExecutorArgs(TypedDict):
150
+ """``ExecutorCreated`` and ``ExternalStateExecutorDeployed``."""
151
+
152
+ executor: ChecksumAddress
153
+ marketId: MarketId
154
+
155
+
156
+ class ExternalStateOperationArgs(TypedDict):
157
+ """``ExternalStateOperationFuseEnter`` and ``ExternalStateOperationFuseExit``;
158
+ ``version`` is the operation fuse's address."""
159
+
160
+ version: FuseAddress
161
+ asset: ChecksumAddress
162
+ amount: Amount
163
+ balanceAccount: ChecksumAddress
164
+ valueInUnderlying: Amount
165
+ actionsCount: int
166
+
167
+
168
+ #: The parameters of one ExternalState event, by its Solidity names; tell the
169
+ #: shapes apart by ``ExternalStateEvent.name`` or a key (``"signer" in args``).
170
+ ExternalStateEventArgs: TypeAlias = (
171
+ ExternalStateBigChangeDetectedArgs
172
+ | ExternalStateCustodianTimestampUpdatedArgs
173
+ | ExternalStateTotalBalanceUpdatedArgs
174
+ | ExternalStateUnpausedArgs
175
+ | ExternalStateAssetRescuedArgs
176
+ | ExternalStateExecutorArgs
177
+ | ExternalStateOperationArgs
178
+ )
179
+
180
+ #: Event name -> the TypedDict its ``args`` is.
181
+ EXTERNAL_STATE_EVENT_ARGS: dict[str, type] = {
182
+ "ExternalStateBigChangeDetected": ExternalStateBigChangeDetectedArgs,
183
+ "ExternalStateBalanceFuseLastCustodianTimestampUpdated": (
184
+ ExternalStateCustodianTimestampUpdatedArgs
185
+ ),
186
+ "ExternalStateBalanceFuseLastTotalBalanceUpdated": (
187
+ ExternalStateTotalBalanceUpdatedArgs
188
+ ),
189
+ "ExternalStateUnpaused": ExternalStateUnpausedArgs,
190
+ "ExternalStateAssetRescued": ExternalStateAssetRescuedArgs,
191
+ "ExecutorCreated": ExternalStateExecutorArgs,
192
+ "ExternalStateOperationFuseEnter": ExternalStateOperationArgs,
193
+ "ExternalStateOperationFuseExit": ExternalStateOperationArgs,
194
+ "ExternalStateExecutorDeployed": ExternalStateExecutorArgs,
195
+ }
196
+
117
197
  #: topic0 -> spec, for every ExternalState event the vault emits.
118
198
  EXTERNAL_STATE_EVENTS: dict[bytes, ExternalStateEventSpec] = {
119
199
  spec.topic: spec for spec in EXTERNAL_STATE_EVENT_SPECS
@@ -130,7 +210,7 @@ class ExternalStateEvent:
130
210
 
131
211
  name: str
132
212
  emitter: ChecksumAddress
133
- args: dict[str, Any]
213
+ args: ExternalStateEventArgs
134
214
  block_number: int | None = None
135
215
  transaction_hash: TxHash | None = None
136
216
  log_index: int | None = None
@@ -230,10 +310,15 @@ def decode_external_state_event( # proctor: ignore[primitives-untyped-dict]
230
310
  values = decode([abi_type for abi_type, _ in spec.params], raw)
231
311
  except DecodingError as exc:
232
312
  raise ExternalStateEventDecodeError(f"{spec.name}: {exc}") from exc
233
- args = {
234
- name: Web3.to_checksum_address(value) if abi_type == "address" else value
235
- for (abi_type, name), value in zip(spec.params, values, strict=True)
236
- }
313
+ # Each value is narrowed to its ABI type; the key set is the spec's, which
314
+ # EXTERNAL_STATE_EVENT_ARGS mirrors (pinned by the tests).
315
+ args = cast(
316
+ ExternalStateEventArgs,
317
+ {
318
+ name: abi_value(abi_type, value)
319
+ for (abi_type, name), value in zip(spec.params, values, strict=True)
320
+ },
321
+ )
237
322
  address = log.get("address")
238
323
  if not isinstance(address, str | bytes):
239
324
  raise ExternalStateEventDecodeError(f"{spec.name}: emitter")