ipor-fusion 4.0.0.dev156__tar.gz → 4.0.0.dev162__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 (304) hide show
  1. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/AGENTS.md +7 -5
  2. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/MIGRATION_4.md +62 -0
  3. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/PKG-INFO +1 -1
  4. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/pyproject.toml +1 -1
  5. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/__init__.py +86 -0
  6. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/oracle_mapping_view.py +9 -5
  7. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/context.py +2 -3
  8. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/contract.py +6 -6
  9. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/external_state_executor.py +15 -7
  10. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/plasma_vault.py +16 -14
  11. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/simulation.py +124 -40
  12. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/__init__.py +36 -0
  13. ipor_fusion-4.0.0.dev162/src/ipor_fusion/fuses/events.py +45 -0
  14. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/external_state_events.py +93 -8
  15. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/hypercore_events.py +185 -10
  16. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/mcp/models.py +251 -39
  17. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/__init__.py +26 -0
  18. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/hypercore.py +2 -2
  19. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/oracle_mapping_nodes.py +158 -10
  20. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_data.py +155 -61
  21. ipor_fusion-4.0.0.dev162/tests/_event_args.py +29 -0
  22. ipor_fusion-4.0.0.dev162/tests/fixtures/simulate_v1_request.json +1 -0
  23. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_oracle_mapping.py +13 -5
  24. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_vault_predates_getters.py +9 -9
  25. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_external_state_events.py +23 -0
  26. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_external_state_executor.py +12 -0
  27. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_events.py +20 -7
  28. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_mcp_models.py +159 -17
  29. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_mcp_server.py +1 -1
  30. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_oracle_mapping.py +59 -43
  31. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_public_api.py +71 -0
  32. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_validation.py +20 -20
  33. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_vault_simulator_blocks.py +62 -1
  34. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/typed_client/consumer.py +31 -0
  35. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/typed_client/rejected.py +17 -0
  36. ipor_fusion-4.0.0.dev156/src/ipor_fusion/fuses/events.py +0 -25
  37. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.claude-plugin/marketplace.json +0 -0
  38. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.claude-plugin/plugin.json +0 -0
  39. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.env.example +0 -0
  40. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.gemini/settings.json +0 -0
  41. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.git-blame-ignore-revs +0 -0
  42. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.github/workflows/cd.yml +0 -0
  43. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.github/workflows/ci.yml +0 -0
  44. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.github/workflows/commit-lint.yml +0 -0
  45. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.github/workflows/notify-slack.yml +0 -0
  46. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.github/workflows/python-build.yml +0 -0
  47. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.github/workflows/python-publish.yml +0 -0
  48. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.github/workflows/release.yml +0 -0
  49. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.github/workflows/report-slack.yml +0 -0
  50. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.gitignore +0 -0
  51. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.mcp.json +0 -0
  52. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.pre-commit-config.yaml +0 -0
  53. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/.python-version +0 -0
  54. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/CHANGELOG.md +0 -0
  55. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/CLAUDE.md +0 -0
  56. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/CODEOWNERS +0 -0
  57. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/LICENSE +0 -0
  58. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/README.md +0 -0
  59. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/build.sh +0 -0
  60. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/examples/CONTRIBUTING.md +0 -0
  61. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/examples/README.md +0 -0
  62. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  63. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  64. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  65. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  66. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/examples/external_state_margin_leg_base.py +0 -0
  67. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/examples/simple_aave_v3_supply_base.py +0 -0
  68. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/pytest.ini +0 -0
  69. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/scripts/commit-check.sh +0 -0
  70. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/scripts/crosschain_readiness.py +0 -0
  71. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/skills/ipor-deploy-vault/SKILL.md +0 -0
  72. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/about.py +0 -0
  73. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cache.py +0 -0
  74. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/chains.py +0 -0
  75. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/__init__.py +0 -0
  76. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  77. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/config_cmd.py +0 -0
  78. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/config_store.py +0 -0
  79. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/main.py +0 -0
  80. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/market_cmd.py +0 -0
  81. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/options.py +0 -0
  82. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  83. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_health.py +0 -0
  84. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  85. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  86. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  87. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/config/__init__.py +0 -0
  88. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/config/roles.py +0 -0
  89. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/__init__.py +0 -0
  90. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/access.py +0 -0
  91. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/address.py +0 -0
  92. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/erc20.py +0 -0
  93. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/fee_manager.py +0 -0
  94. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/fuse.py +0 -0
  95. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/fuse_action.py +0 -0
  96. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/fusion_factory.py +0 -0
  97. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/logs.py +0 -0
  98. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/multicall.py +0 -0
  99. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/oracle.py +0 -0
  100. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/rewards_manager.py +0 -0
  101. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  102. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/__init__.py +0 -0
  103. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  104. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  105. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  106. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  107. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  108. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  109. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  110. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  111. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  112. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/contracts.py +0 -0
  113. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/discovery.py +0 -0
  114. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/errors.py +0 -0
  115. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  116. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  117. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  118. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  119. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/lane.py +0 -0
  120. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/logs.py +0 -0
  121. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/messages.py +0 -0
  122. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/simulation.py +0 -0
  123. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  124. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  125. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  126. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  127. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  128. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/transport.py +0 -0
  129. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/dependency_graph.py +0 -0
  130. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/entry_cli.py +0 -0
  131. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/entry_mcp.py +0 -0
  132. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/errors.py +0 -0
  133. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/explorer.py +0 -0
  134. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/field_docs.py +0 -0
  135. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  136. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/async_action.py +0 -0
  137. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/base.py +0 -0
  138. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  139. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/erc4626.py +0 -0
  140. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  141. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/external_state.py +0 -0
  142. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  143. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  144. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/hypercore.py +0 -0
  145. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/merkl.py +0 -0
  146. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/morpho.py +0 -0
  147. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  148. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  149. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/universal.py +0 -0
  150. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/__init__.py +0 -0
  151. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/architecture.md +0 -0
  152. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/glossary.md +0 -0
  153. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/invariants.md +0 -0
  154. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/quickstart.md +0 -0
  155. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/market_ids.py +0 -0
  156. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/market_info.py +0 -0
  157. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/mcp/__init__.py +0 -0
  158. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/mcp/guide.py +0 -0
  159. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/mcp/server.py +0 -0
  160. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/morpho_api.py +0 -0
  161. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/py.typed +0 -0
  162. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/aave_v3.py +0 -0
  163. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/aave_v4.py +0 -0
  164. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/compound_v3.py +0 -0
  165. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  166. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/lending_health.py +0 -0
  167. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/morpho.py +0 -0
  168. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  169. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  170. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/position_manager.py +0 -0
  171. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  172. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  173. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/unpriceable.py +0 -0
  174. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/substrates.py +0 -0
  175. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/types.py +0 -0
  176. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/validation.py +0 -0
  177. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_erc20.py +0 -0
  178. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_info.py +0 -0
  179. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_managers.py +0 -0
  180. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_positions.py +0 -0
  181. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_reads.py +0 -0
  182. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/UniswapV3UniversalRouter.py +0 -0
  183. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_crosschain.py +0 -0
  184. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_crosschain_lifecycle.py +0 -0
  185. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_crosschain_recovery.py +0 -0
  186. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_euler_v2.py +0 -0
  187. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_foundry.py +0 -0
  188. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_guide.py +0 -0
  189. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_hypercore_model.py +0 -0
  190. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_hypercore_shadow.py +0 -0
  191. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_multicall.py +0 -0
  192. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_simulate.py +0 -0
  193. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/_validation.py +0 -0
  194. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/addresses.py +0 -0
  195. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/conftest.py +0 -0
  196. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/constants.py +0 -0
  197. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  198. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/fixtures/hypercore_market55.json +0 -0
  199. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/fixtures/vault_info_golden/clean.json +0 -0
  200. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  201. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/fixtures/vault_info_golden/rich.json +0 -0
  202. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  203. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_about.py +0 -0
  204. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_access_manager.py +0 -0
  205. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cache.py +0 -0
  206. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_chains.py +0 -0
  207. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_changelog.py +0 -0
  208. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_commands.py +0 -0
  209. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_config_store.py +0 -0
  210. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_helpers.py +0 -0
  211. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_hypercore.py +0 -0
  212. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_lending_health.py +0 -0
  213. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_market_morpho_blue.py +0 -0
  214. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_pending_requests_scan.py +0 -0
  215. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_role_accounts.py +0 -0
  216. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_vault_info_golden.py +0 -0
  217. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_cli_vault_validate.py +0 -0
  218. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_contract_call.py +0 -0
  219. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_contract_encoder.py +0 -0
  220. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_ccip_events.py +0 -0
  221. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_ccip_indexer.py +0 -0
  222. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_ccip_quote.py +0 -0
  223. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_chainlink.py +0 -0
  224. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_contracts.py +0 -0
  225. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_encoding.py +0 -0
  226. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_errors.py +0 -0
  227. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_lane.py +0 -0
  228. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_layering.py +0 -0
  229. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_readiness.py +0 -0
  230. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_readiness_report.py +0 -0
  231. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_transport.py +0 -0
  232. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_docs_typing.py +0 -0
  233. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_erc20.py +0 -0
  234. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_error_hierarchy.py +0 -0
  235. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_examples_composed_hypercore.py +0 -0
  236. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_examples_crosschain.py +0 -0
  237. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  238. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_examples_vaults.py +0 -0
  239. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_explorer.py +0 -0
  240. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_fee_manager.py +0 -0
  241. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_fuse_encoding.py +0 -0
  242. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_fusion_instance.py +0 -0
  243. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_guide.py +0 -0
  244. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_deployment.py +0 -0
  245. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_flow.py +0 -0
  246. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_live.py +0 -0
  247. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_outcome.py +0 -0
  248. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_readers.py +0 -0
  249. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_simulation.py +0 -0
  250. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_logs.py +0 -0
  251. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_mcp_hypercore.py +0 -0
  252. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_mcp_vault_validate.py +0 -0
  253. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_multicall.py +0 -0
  254. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_oracle.py +0 -0
  255. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_plasma_vault.py +0 -0
  256. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_public_type_reachability.py +0 -0
  257. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_reader_encoding.py +0 -0
  258. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_readiness_selection.py +0 -0
  259. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_revert_decoding.py +0 -0
  260. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_rewards_manager.py +0 -0
  261. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_roles.py +0 -0
  262. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_sdk_layering.py +0 -0
  263. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  264. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  265. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  266. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_crosschain_canary.py +0 -0
  267. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_crosschain_hypercore.py +0 -0
  268. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  269. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  270. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  271. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  272. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  273. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  274. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  275. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_examples_arbitrum.py +0 -0
  276. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_examples_base.py +0 -0
  277. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_examples_crosschain.py +0 -0
  278. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_external_state_executor_base.py +0 -0
  279. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  280. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  281. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  282. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_morpho_blue.py +0 -0
  283. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_pilot_v3.py +0 -0
  284. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  285. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  286. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  287. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  288. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_readers_integration.py +0 -0
  289. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_release_funds.py +0 -0
  290. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_swap_on_base.py +0 -0
  291. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  292. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_simulation_observation.py +0 -0
  293. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_solidity_compiler.py +0 -0
  294. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_solidity_mirrors.py +0 -0
  295. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_substrates.py +0 -0
  296. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_types_and_events.py +0 -0
  297. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_unpriceable_tokens.py +0 -0
  298. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_vault_data_block.py +0 -0
  299. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_vault_dep_graph.py +0 -0
  300. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_vault_info_onchain_base.py +0 -0
  301. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  302. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_web3_context.py +0 -0
  303. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/tests/test_withdraw_manager.py +0 -0
  304. {ipor_fusion-4.0.0.dev156 → ipor_fusion-4.0.0.dev162}/uv.lock +0 -0
@@ -449,11 +449,13 @@ schema. Adding a field to `build_vault_info_json` (or a `fusion market` document
449
449
  means adding it to its TypedDict, to the matching model (with a default for
450
450
  back-compat) and to the `_full_vault_info_dict` fixture;
451
451
  `TestTypedDocumentsMirrorModels` in `test_mcp_models.py` holds every TypedDict to
452
- its model block by block. The model keeps `dict[str, Any]` where the schema is
453
- deliberately loose (`substrates`, `deployment`, `share_price`, `dependency_graph`,
454
- `position_breakdown`): the SDK types those blocks, the schema does not validate
455
- their inner keys. The substrate entries stay open-ended on both sides
456
- (`SubstrateEntryJson`, `dict[str, str | bool]`): each decoder adds its own fields.
452
+ its model block by block, a union block (`deployment`, `position_breakdown`,
453
+ `source_detail`) shape by shape. Every block is a model; a block whose optional keys
454
+ the producer omits is a `_Sparse` model, which dumps only the fields it was given,
455
+ so the key stays absent rather than null. `TestNestedBlocksDumpVerbatim` pins that
456
+ the typed blocks dump exactly what the producer wrote. The substrate entries stay
457
+ open-ended on both sides (`SubstrateEntryJson`, `dict[str, str | bool]`): each
458
+ decoder adds its own fields.
457
459
 
458
460
  ## Domain rules (verified against the contracts)
459
461
 
@@ -741,6 +741,28 @@ fuse's `eid=` take it (`LayerZeroEid(30101)`). CCIP chain selectors are
741
741
  (`CcipChainSelector(4949039107694359620)`). `ZERO_ADDRESS` is a `ChecksumAddress`
742
742
  (same value).
743
743
 
744
+ **Simulation.** The `VaultSimulator` override methods name the keys `eth_simulateV1`
745
+ accepts instead of taking `**Any`; the keys and the request they produce are
746
+ unchanged. `with_state_override(address, **overrides)` takes `AccountOverride` keys
747
+ (`balance`, `nonce`, `code`, `movePrecompileToAddress`: `0x` hex strings; `state`,
748
+ `stateDiff`: `0x` slot to `0x` word), and a `StateOverrideProvider` returns
749
+ `Mapping[str, AccountOverride]`. `with_block_override(**fields)` takes
750
+ `BlockOverrides` keys (`number`, `time`, `gasLimit`, `baseFeePerGas`, `blobBaseFee`:
751
+ an `int`, sent as hex, or a hex string; `feeRecipient`, `prevRandao`: strings) and
752
+ raises `TypeError` for any other value type (`withdrawals` is not supported).
753
+ Both TypedDicts are exported from `ipor_fusion`. A misspelled key or an `int` balance
754
+ now fails type checking instead of reaching the node:
755
+
756
+ ```python
757
+ sim.with_state_override(holder, balance=hex(10**18), nonce=hex(0))
758
+ sim.with_block_override(gasLimit=30_000_000)
759
+ sim.with_state_override_provider(lambda n: {oracle: {"code": code_hex}})
760
+ ```
761
+
762
+ `add_transaction(transaction)` takes web3's `TxParams`, the shape
763
+ `Call.build_transaction` returns; a node-shaped dict carrying `input` instead of `data`
764
+ is still accepted at run time.
765
+
744
766
  **HyperCore (preview).** The fuses, `HyperCoreSubstrates`, `HyperCoreReader`,
745
767
  `read_hypercore_transfer_snapshot` and the helpers `system_address`,
746
768
  `precompile_index_of`, `perp_dex_of`, `is_native_perp_asset`, `is_hip3_asset` take the
@@ -774,6 +796,11 @@ except as listed under [Behavior changes](#behavior-changes)): `chain_id` fields
774
796
  string). Calling an MCP tool function
775
797
  directly from Python takes `ChainId`. Their amount, decimals and time fields stay
776
798
  `int`: they are JSON output models, and the SDK values above fit them unchanged.
799
+ The nested blocks that were `dict[str, Any]` are models now (`deployment`,
800
+ `share_price`, `links`, `dependency_graph`, a balance fuse's `position_breakdown`, an
801
+ oracle node's `source_detail`, the Morpho `asset`, `adapters`, `caps`,
802
+ `liquidity_adapter`, `public_allocator` and `allocations`): read them by attribute
803
+ (`result.caps[0].loan_token`, not `["loan_token"]`).
777
804
 
778
805
  ## Typed JSON documents
779
806
 
@@ -787,6 +814,7 @@ untyped code needs none of this section.
787
814
  | `build_morpho_blue_market_json` | `MorphoBlueMarketJson` |
788
815
  | `build_meta_morpho_json` | `MetaMorphoV1Json \| MetaMorphoV2Json`, told apart by `doc["version"]` |
789
816
  | `RoleAccount.to_dict` | `RoleAccountJson` |
817
+ | `OracleMapping.to_dict` / `OracleNode.to_dict` | `OracleMappingJson` / `OracleNodeJson` |
790
818
 
791
819
  Every nested block has its own TypedDict (`FeesJson`, `WithdrawManagerJson`,
792
820
  `BalanceFuseJson`, `ReconciliationJson`, `HyperCoreJson`, `MorphoSupplyingVaultJson`,
@@ -813,12 +841,46 @@ that only some entries carry is `NotRequired` (a balance fuse's `pct_of_total` a
813
841
  age) or `DeploymentErrorJson` (`{"error": ...}`) or `None`; `share_price` is
814
842
  `SharePriceJson` (`asset`, and `usd` when the asset is priced); `dependency_graph`
815
843
  is `DependencyGraphJson` (`edges`, `update_reach`, `update_groups`).
844
+ - `OracleNode.source_detail` is `SourceDetailJson`, one TypedDict per feed kind
845
+ (`ChainlinkDetailJson`, `DualXrefDetailJson`, `Erc4626DetailJson`,
846
+ `MorphoFeedDetailJson`, `MiddlewareFallbackDetailJson`; importable from
847
+ `ipor_fusion` and `ipor_fusion.readers`). Narrow by a key before reading a
848
+ kind-specific one: `if detail is not None and "aggregator" in detail:
849
+ detail["description"]`.
850
+ - Event `args` are typed per event kind: `ExternalStateEvent.args` is
851
+ `ExternalStateEventArgs` and `HyperCoreEvent.args` is `HyperCoreEventArgs`, a union
852
+ of one TypedDict per event (`ExternalStateUnpausedArgs`,
853
+ `HyperCoreDepositFuseEnterArgs`, ...; `EXTERNAL_STATE_EVENT_ARGS` /
854
+ `HYPERCORE_EVENT_ARGS` map an event name to its shape). Values carry nominal types
855
+ (`Amount`, `MarketId`, `FuseAddress`, `HyperCoreTokenIndex`, `PayloadHash`, web3's
856
+ `Timestamp`, ...). `event.args["signer"]` no longer type-checks on its own: narrow
857
+ with a key test (`if "signer" in event.args:`). `HyperCoreEvent.fuse` is a
858
+ `FuseAddress | None`.
859
+ - `RawLog` (the log shape `ExternalStateExecutor.parse_balance_proposed` /
860
+ `find_balance_proposed` accept) is `Mapping[str, object]`, not `Mapping[str, Any]`;
861
+ a web3 `LogReceipt` still fits it.
816
862
 
817
863
  ## Behavior changes
818
864
 
819
865
  These apply to every caller, type-checked or not. Changes described in full above
820
866
  are listed with a link.
821
867
 
868
+ - **MCP `outputSchema` describes every nested block.** The tool output is
869
+ byte-identical; the schemas of `vault_info`, `vault_oracle_mapping`,
870
+ `market_morpho_blue` and `market_meta_morpho` replace each free-form object with
871
+ the block's own definition: `links` (`VaultLinks`), `deployment`
872
+ (`DeploymentModel` or `DeploymentErrorModel`), `share_price` (`SharePriceModel`),
873
+ `dependency_graph` (`DependencyGraphModel`), `position_breakdown` (a list of
874
+ `MorphoBreakdownEntry` or of `AaveBreakdownEntry`, amounts `BreakdownAmount`),
875
+ substrate entries (string or boolean values), `source_detail` (`ChainlinkDetail`,
876
+ `DualXrefDetail`, `Erc4626Detail`, `MorphoFeedDetail` or
877
+ `MiddlewareFallbackDetail`), a supplying vault's `asset` (`MorphoVaultAssetModel`)
878
+ and the MetaMorpho `asset`, `liquidity_adapter` / `adapters`, `caps`,
879
+ `public_allocator` (with `flow_caps`) and `allocations`. Fixed-shape blocks now declare their
880
+ required and optional fields and reject unknown keys (`additionalProperties:
881
+ false`), as the documents always wrote them; substrate entries and keyed maps
882
+ (`flow_caps`, `edges`, `update_reach`) stay open with typed values.
883
+
822
884
  - **Vault reads are pinned to one block**: every read of `fetch_vault_data`, log
823
885
  scans included, runs at the resolved block; see
824
886
  [Vault reads and validation](#vault-reads-and-validation).
@@ -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.dev162
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.dev162"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -72,6 +72,8 @@ from ipor_fusion.core.plasma_vault import (
72
72
  )
73
73
  from ipor_fusion.core.rewards_manager import RewardsManager, VestingData
74
74
  from ipor_fusion.core.simulation import (
75
+ AccountOverride,
76
+ BlockOverrides,
75
77
  SimulatedCallResult,
76
78
  SimulationObservation,
77
79
  SimulationResult,
@@ -314,15 +316,44 @@ from ipor_fusion.fuses import (
314
316
  system_address,
315
317
  )
316
318
  from ipor_fusion.fuses.external_state_events import (
319
+ EXTERNAL_STATE_EVENT_ARGS,
317
320
  EXTERNAL_STATE_EVENT_SPECS,
318
321
  EXTERNAL_STATE_EVENTS,
319
322
  EXTERNAL_STATE_TOPICS,
323
+ ExternalStateAssetRescuedArgs,
324
+ ExternalStateBigChangeDetectedArgs,
325
+ ExternalStateCustodianTimestampUpdatedArgs,
320
326
  ExternalStateEvent,
327
+ ExternalStateEventArgs,
321
328
  ExternalStateEventSpec,
329
+ ExternalStateExecutorArgs,
330
+ ExternalStateOperationArgs,
331
+ ExternalStateTotalBalanceUpdatedArgs,
332
+ ExternalStateUnpausedArgs,
322
333
  decode_external_state_event,
323
334
  external_state_event_name,
324
335
  external_state_events,
325
336
  )
337
+ from ipor_fusion.fuses.hypercore_events import (
338
+ HYPERCORE_EVENT_ARGS,
339
+ HyperCoreActionEnqueuedArgs,
340
+ HyperCoreActionSettledArgs,
341
+ HyperCoreBuilderFeeFuseEnterArgs,
342
+ HyperCoreCancelByCloidArgs,
343
+ HyperCoreCancelByOidArgs,
344
+ HyperCoreDepositFuseEnterArgs,
345
+ HyperCoreEventArgs,
346
+ HyperCoreMarginFuseEnterArgs,
347
+ HyperCoreObserverSetChangedArgs,
348
+ HyperCoreObserverSetProposedArgs,
349
+ HyperCoreOrderFuseEnterArgs,
350
+ HyperCoreRecoveryExecutedArgs,
351
+ HyperCoreRecoveryProposedArgs,
352
+ HyperCoreReportedActionSettledArgs,
353
+ HyperCoreReportSubmittedArgs,
354
+ HyperCoreSendFuseSendAssetArgs,
355
+ HyperCoreSendFuseSpotSendArgs,
356
+ )
326
357
  from ipor_fusion.market_ids import IporFusionMarkets
327
358
  from ipor_fusion.market_info import (
328
359
  MetaMorphoAdapterJson,
@@ -422,6 +453,20 @@ from ipor_fusion.readers import (
422
453
  read_hypercore_transfer_snapshot,
423
454
  read_hypercore_vault_state,
424
455
  )
456
+ from ipor_fusion.readers.oracle_mapping_nodes import (
457
+ AggregatorDetailJson,
458
+ AggregatorFeedDetailJson,
459
+ ChainlinkDetailJson,
460
+ DualXrefDetailJson,
461
+ Erc4626DetailJson,
462
+ MiddlewareFallbackDetailJson,
463
+ MorphoFeedDetailJson,
464
+ OracleAssetJson,
465
+ OracleMappingJson,
466
+ OracleNodeJson,
467
+ OraclePriceJson,
468
+ SourceDetailJson,
469
+ )
425
470
  from ipor_fusion.substrates import (
426
471
  SubstrateInfo,
427
472
  decode_substrate,
@@ -546,6 +591,15 @@ __all__ = [
546
591
  "EXTERNAL_STATE_EVENTS",
547
592
  "EXTERNAL_STATE_TOPICS",
548
593
  "ExternalStateEvent",
594
+ "EXTERNAL_STATE_EVENT_ARGS",
595
+ "ExternalStateAssetRescuedArgs",
596
+ "ExternalStateBigChangeDetectedArgs",
597
+ "ExternalStateCustodianTimestampUpdatedArgs",
598
+ "ExternalStateEventArgs",
599
+ "ExternalStateExecutorArgs",
600
+ "ExternalStateOperationArgs",
601
+ "ExternalStateTotalBalanceUpdatedArgs",
602
+ "ExternalStateUnpausedArgs",
549
603
  "ExternalStateEventDecodeError",
550
604
  "ExternalStateEventSpec",
551
605
  "decode_external_state_event",
@@ -554,6 +608,24 @@ __all__ = [
554
608
  "HYPERCORE_EVENTS",
555
609
  "HYPERCORE_EVENT_SPECS",
556
610
  "HyperCoreEvent",
611
+ "HYPERCORE_EVENT_ARGS",
612
+ "HyperCoreActionEnqueuedArgs",
613
+ "HyperCoreActionSettledArgs",
614
+ "HyperCoreBuilderFeeFuseEnterArgs",
615
+ "HyperCoreCancelByCloidArgs",
616
+ "HyperCoreCancelByOidArgs",
617
+ "HyperCoreDepositFuseEnterArgs",
618
+ "HyperCoreEventArgs",
619
+ "HyperCoreMarginFuseEnterArgs",
620
+ "HyperCoreObserverSetChangedArgs",
621
+ "HyperCoreObserverSetProposedArgs",
622
+ "HyperCoreOrderFuseEnterArgs",
623
+ "HyperCoreRecoveryExecutedArgs",
624
+ "HyperCoreRecoveryProposedArgs",
625
+ "HyperCoreReportSubmittedArgs",
626
+ "HyperCoreReportedActionSettledArgs",
627
+ "HyperCoreSendFuseSendAssetArgs",
628
+ "HyperCoreSendFuseSpotSendArgs",
557
629
  "HyperCoreEventSpec",
558
630
  "decode_hypercore_event",
559
631
  "find_hypercore_events",
@@ -579,6 +651,8 @@ __all__ = [
579
651
  "MULTICALL3_ADDRESS",
580
652
  "VaultSimulator",
581
653
  "StateOverrideProvider",
654
+ "AccountOverride",
655
+ "BlockOverrides",
582
656
  "SimulationObservation",
583
657
  "SimulationResult",
584
658
  "SimulatedCallResult",
@@ -945,6 +1019,18 @@ __all__ = [
945
1019
  "OracleAsset",
946
1020
  "OracleMapping",
947
1021
  "OracleNode",
1022
+ "AggregatorDetailJson",
1023
+ "AggregatorFeedDetailJson",
1024
+ "ChainlinkDetailJson",
1025
+ "DualXrefDetailJson",
1026
+ "Erc4626DetailJson",
1027
+ "MiddlewareFallbackDetailJson",
1028
+ "MorphoFeedDetailJson",
1029
+ "OracleAssetJson",
1030
+ "OracleMappingJson",
1031
+ "OracleNodeJson",
1032
+ "OraclePriceJson",
1033
+ "SourceDetailJson",
948
1034
  "OraclePrice",
949
1035
  "build_oracle_mapping",
950
1036
  "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)}")
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
  import copy
4
4
  import logging
5
5
  import threading
6
- from typing import Any
7
6
 
8
7
  from eth_account import Account
9
8
  from eth_typing import ChecksumAddress, HexStr
@@ -453,7 +452,7 @@ class InFlightLimit:
453
452
  def _slot_middleware(slots: threading.BoundedSemaphore) -> type[Web3Middleware]:
454
453
  class InFlightLimitMiddleware(Web3Middleware):
455
454
  def wrap_make_request(self, make_request: MakeRequestFn) -> MakeRequestFn:
456
- def limited(method: RPCEndpoint, params: Any) -> RPCResponse:
455
+ def limited(method: RPCEndpoint, params: object) -> RPCResponse:
457
456
  with slots:
458
457
  return make_request(method, params)
459
458
 
@@ -463,7 +462,7 @@ def _slot_middleware(slots: threading.BoundedSemaphore) -> type[Web3Middleware]:
463
462
  self, make_batch_request: MakeBatchRequestFn
464
463
  ) -> MakeBatchRequestFn:
465
464
  def limited(
466
- requests_info: list[tuple[RPCEndpoint, Any]],
465
+ requests_info: list[tuple[RPCEndpoint, object]],
467
466
  ) -> list[RPCResponse] | RPCResponse:
468
467
  with slots:
469
468
  return make_batch_request(requests_info)
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Callable
4
4
  from dataclasses import dataclass
5
- from typing import Any, Generic, TypeVar, cast
5
+ from typing import Generic, TypeVar, cast
6
6
 
7
7
  from eth_abi import decode, encode
8
8
  from eth_typing import ChecksumAddress
@@ -60,7 +60,7 @@ class Call(Generic[T_co]):
60
60
  raise ValueError("cannot map a write-only Call without output types")
61
61
  decoder = self.decoder
62
62
 
63
- def mapped(value: Any) -> U:
63
+ def mapped(value: object) -> U:
64
64
  decoded = decoder(value) if decoder is not None else cast(T_co, value)
65
65
  return transform(decoded)
66
66
 
@@ -101,7 +101,7 @@ class Call(Generic[T_co]):
101
101
  if not self.output_types:
102
102
  raise ValueError("Call.decode() on a write-only Call.")
103
103
  values = tuple(decode(self.output_types, bytes(raw)))
104
- single: Any = values[0] if len(values) == 1 else values
104
+ single: object = values[0] if len(values) == 1 else values
105
105
  if self.decoder is not None:
106
106
  return self.decoder(single)
107
107
  return cast(T_co, single)
@@ -148,7 +148,7 @@ class ContractWrapper:
148
148
  def _view(
149
149
  self,
150
150
  signature: str,
151
- *args: Any,
151
+ *args: object,
152
152
  output_types: list[str],
153
153
  decoder: Callable[..., T] | None = None,
154
154
  ) -> Call[T]:
@@ -159,11 +159,11 @@ class ContractWrapper:
159
159
  decoder=decoder,
160
160
  )
161
161
 
162
- def _write(self, signature: str, *args: Any) -> Call[None]:
162
+ def _write(self, signature: str, *args: object) -> Call[None]:
163
163
  return Call(to=self._address, data=_encode_calldata(signature, *args))
164
164
 
165
165
 
166
- def _encode_calldata(signature: str, *args: Any) -> bytes:
166
+ def _encode_calldata(signature: str, *args: object) -> bytes:
167
167
  selector = function_signature_to_4byte_selector(signature)
168
168
  types = _parse_param_types(signature)
169
169
  return selector + encode(types, list(args)) if types else selector
@@ -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.
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from collections.abc import Callable, Sequence
4
4
  from concurrent.futures import ThreadPoolExecutor
5
5
  from dataclasses import dataclass
6
- from typing import Any, TypeVar
6
+ from typing import TypeVar, cast
7
7
 
8
8
  from eth_abi import decode, encode
9
9
  from eth_typing import ChecksumAddress
@@ -91,19 +91,21 @@ def _market_id_list_decoder(value: list) -> list[MarketId]:
91
91
  _BALANCE_OF_SELECTOR = function_signature_to_4byte_selector("balanceOf()")
92
92
 
93
93
 
94
+ def _read_result_data(result: tuple[bytes]) -> bytes:
95
+ """``ReadResult.data``, undecoded."""
96
+ return bytes(result[0])
97
+
98
+
94
99
  def _universal_read_decoder(
95
- output_types: list[str] | None, decoder: Callable[..., Any] | None
96
- ) -> Callable[[tuple], Any]:
97
- """Unwrap ``ReadResult.data`` and, given ``output_types``, decode it the way
98
- `Call.decode` decodes a view's return data."""
99
-
100
- def _decode(result: tuple) -> Any:
101
- payload = bytes(result[0])
102
- if output_types is None:
103
- return payload
104
- values = tuple(decode(output_types, payload))
105
- single: Any = values[0] if len(values) == 1 else values
106
- return decoder(single) if decoder is not None else single
100
+ output_types: list[str], decoder: Callable[..., T] | None
101
+ ) -> Callable[[tuple[bytes]], T]:
102
+ """Unwrap ``ReadResult.data`` and decode it the way `Call.decode` decodes a
103
+ view's return data."""
104
+
105
+ def _decode(result: tuple[bytes]) -> T:
106
+ values = tuple(decode(output_types, _read_result_data(result)))
107
+ single: object = values[0] if len(values) == 1 else values
108
+ return decoder(single) if decoder is not None else cast(T, single)
107
109
 
108
110
  return _decode
109
111
 
@@ -265,7 +267,7 @@ class PlasmaVault(ContractWrapper):
265
267
  target,
266
268
  data,
267
269
  output_types=["(bytes)"],
268
- decoder=_universal_read_decoder(None, None),
270
+ decoder=_read_result_data,
269
271
  )
270
272
 
271
273
  def universal_read_decoded(