ipor-fusion 4.0.0.dev159__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 (303) hide show
  1. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/AGENTS.md +7 -5
  2. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/MIGRATION_4.md +43 -0
  3. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/PKG-INFO +1 -1
  4. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/pyproject.toml +1 -1
  5. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/__init__.py +4 -0
  6. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/context.py +2 -3
  7. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/contract.py +6 -6
  8. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/plasma_vault.py +16 -14
  9. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/simulation.py +124 -40
  10. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/mcp/models.py +251 -41
  11. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/hypercore.py +2 -2
  12. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_data.py +155 -61
  13. ipor_fusion-4.0.0.dev162/tests/fixtures/simulate_v1_request.json +1 -0
  14. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_vault_predates_getters.py +9 -9
  15. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_mcp_models.py +145 -15
  16. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_mcp_server.py +1 -1
  17. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_public_api.py +2 -0
  18. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_validation.py +20 -20
  19. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_vault_simulator_blocks.py +62 -1
  20. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/typed_client/consumer.py +3 -0
  21. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/typed_client/rejected.py +10 -0
  22. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.claude-plugin/marketplace.json +0 -0
  23. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.claude-plugin/plugin.json +0 -0
  24. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.env.example +0 -0
  25. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.gemini/settings.json +0 -0
  26. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.git-blame-ignore-revs +0 -0
  27. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.github/workflows/cd.yml +0 -0
  28. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.github/workflows/ci.yml +0 -0
  29. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.github/workflows/commit-lint.yml +0 -0
  30. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.github/workflows/notify-slack.yml +0 -0
  31. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.github/workflows/python-build.yml +0 -0
  32. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.github/workflows/python-publish.yml +0 -0
  33. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.github/workflows/release.yml +0 -0
  34. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.github/workflows/report-slack.yml +0 -0
  35. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.gitignore +0 -0
  36. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.mcp.json +0 -0
  37. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.pre-commit-config.yaml +0 -0
  38. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/.python-version +0 -0
  39. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/CHANGELOG.md +0 -0
  40. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/CLAUDE.md +0 -0
  41. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/CODEOWNERS +0 -0
  42. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/LICENSE +0 -0
  43. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/README.md +0 -0
  44. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/build.sh +0 -0
  45. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/examples/CONTRIBUTING.md +0 -0
  46. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/examples/README.md +0 -0
  47. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  48. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  49. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  50. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  51. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/examples/external_state_margin_leg_base.py +0 -0
  52. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/examples/simple_aave_v3_supply_base.py +0 -0
  53. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/pytest.ini +0 -0
  54. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/scripts/commit-check.sh +0 -0
  55. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/scripts/crosschain_readiness.py +0 -0
  56. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/skills/ipor-deploy-vault/SKILL.md +0 -0
  57. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/about.py +0 -0
  58. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cache.py +0 -0
  59. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/chains.py +0 -0
  60. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/__init__.py +0 -0
  61. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  62. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/config_cmd.py +0 -0
  63. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/config_store.py +0 -0
  64. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/main.py +0 -0
  65. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/market_cmd.py +0 -0
  66. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/options.py +0 -0
  67. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  68. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  69. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_health.py +0 -0
  70. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  71. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  72. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  73. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/config/__init__.py +0 -0
  74. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/config/roles.py +0 -0
  75. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/__init__.py +0 -0
  76. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/access.py +0 -0
  77. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/address.py +0 -0
  78. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/erc20.py +0 -0
  79. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/external_state_executor.py +0 -0
  80. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/fee_manager.py +0 -0
  81. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/fuse.py +0 -0
  82. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/fuse_action.py +0 -0
  83. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/fusion_factory.py +0 -0
  84. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/logs.py +0 -0
  85. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/multicall.py +0 -0
  86. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/oracle.py +0 -0
  87. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/rewards_manager.py +0 -0
  88. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  89. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/__init__.py +0 -0
  90. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  91. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  92. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  93. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  94. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  95. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  96. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  97. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  98. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  99. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/contracts.py +0 -0
  100. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/discovery.py +0 -0
  101. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/errors.py +0 -0
  102. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  103. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  104. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  105. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  106. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/lane.py +0 -0
  107. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/logs.py +0 -0
  108. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/messages.py +0 -0
  109. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/simulation.py +0 -0
  110. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  111. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  112. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  113. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  114. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  115. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/crosschain/transport.py +0 -0
  116. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/dependency_graph.py +0 -0
  117. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/entry_cli.py +0 -0
  118. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/entry_mcp.py +0 -0
  119. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/errors.py +0 -0
  120. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/explorer.py +0 -0
  121. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/field_docs.py +0 -0
  122. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/__init__.py +0 -0
  123. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  124. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/async_action.py +0 -0
  125. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/base.py +0 -0
  126. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  127. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/erc4626.py +0 -0
  128. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  129. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/events.py +0 -0
  130. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/external_state.py +0 -0
  131. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/external_state_events.py +0 -0
  132. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  133. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  134. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/hypercore.py +0 -0
  135. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
  136. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/merkl.py +0 -0
  137. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/morpho.py +0 -0
  138. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  139. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  140. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/fuses/universal.py +0 -0
  141. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/__init__.py +0 -0
  142. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/architecture.md +0 -0
  143. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/glossary.md +0 -0
  144. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/invariants.md +0 -0
  145. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/guide/quickstart.md +0 -0
  146. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/market_ids.py +0 -0
  147. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/market_info.py +0 -0
  148. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/mcp/__init__.py +0 -0
  149. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/mcp/guide.py +0 -0
  150. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/mcp/server.py +0 -0
  151. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/morpho_api.py +0 -0
  152. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/py.typed +0 -0
  153. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/__init__.py +0 -0
  154. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/aave_v3.py +0 -0
  155. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/aave_v4.py +0 -0
  156. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/compound_v3.py +0 -0
  157. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  158. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/lending_health.py +0 -0
  159. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/morpho.py +0 -0
  160. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  161. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
  162. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  163. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/position_manager.py +0 -0
  164. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  165. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  166. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/readers/unpriceable.py +0 -0
  167. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/substrates.py +0 -0
  168. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/types.py +0 -0
  169. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/validation.py +0 -0
  170. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_erc20.py +0 -0
  171. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_info.py +0 -0
  172. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_managers.py +0 -0
  173. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_positions.py +0 -0
  174. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/src/ipor_fusion/vault_reads.py +0 -0
  175. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/UniswapV3UniversalRouter.py +0 -0
  176. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_crosschain.py +0 -0
  177. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_crosschain_lifecycle.py +0 -0
  178. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_crosschain_recovery.py +0 -0
  179. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_euler_v2.py +0 -0
  180. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_event_args.py +0 -0
  181. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_foundry.py +0 -0
  182. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_guide.py +0 -0
  183. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_hypercore_model.py +0 -0
  184. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_hypercore_shadow.py +0 -0
  185. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_multicall.py +0 -0
  186. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_simulate.py +0 -0
  187. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/_validation.py +0 -0
  188. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/addresses.py +0 -0
  189. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/conftest.py +0 -0
  190. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/constants.py +0 -0
  191. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  192. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/fixtures/hypercore_market55.json +0 -0
  193. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/fixtures/vault_info_golden/clean.json +0 -0
  194. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  195. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/fixtures/vault_info_golden/rich.json +0 -0
  196. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  197. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_about.py +0 -0
  198. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_access_manager.py +0 -0
  199. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cache.py +0 -0
  200. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_chains.py +0 -0
  201. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_changelog.py +0 -0
  202. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_commands.py +0 -0
  203. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_config_store.py +0 -0
  204. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_helpers.py +0 -0
  205. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_hypercore.py +0 -0
  206. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_lending_health.py +0 -0
  207. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_market_morpho_blue.py +0 -0
  208. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_oracle_mapping.py +0 -0
  209. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_pending_requests_scan.py +0 -0
  210. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_role_accounts.py +0 -0
  211. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_vault_info_golden.py +0 -0
  212. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_cli_vault_validate.py +0 -0
  213. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_contract_call.py +0 -0
  214. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_contract_encoder.py +0 -0
  215. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_ccip_events.py +0 -0
  216. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_ccip_indexer.py +0 -0
  217. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_ccip_quote.py +0 -0
  218. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_chainlink.py +0 -0
  219. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_contracts.py +0 -0
  220. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_encoding.py +0 -0
  221. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_errors.py +0 -0
  222. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_lane.py +0 -0
  223. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_layering.py +0 -0
  224. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_readiness.py +0 -0
  225. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_readiness_report.py +0 -0
  226. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_crosschain_transport.py +0 -0
  227. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_docs_typing.py +0 -0
  228. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_erc20.py +0 -0
  229. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_error_hierarchy.py +0 -0
  230. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_examples_composed_hypercore.py +0 -0
  231. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_examples_crosschain.py +0 -0
  232. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  233. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_examples_vaults.py +0 -0
  234. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_explorer.py +0 -0
  235. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_external_state_events.py +0 -0
  236. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_external_state_executor.py +0 -0
  237. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_fee_manager.py +0 -0
  238. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_fuse_encoding.py +0 -0
  239. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_fusion_instance.py +0 -0
  240. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_guide.py +0 -0
  241. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_deployment.py +0 -0
  242. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_events.py +0 -0
  243. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_flow.py +0 -0
  244. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_live.py +0 -0
  245. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_outcome.py +0 -0
  246. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_readers.py +0 -0
  247. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_hypercore_simulation.py +0 -0
  248. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_logs.py +0 -0
  249. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_mcp_hypercore.py +0 -0
  250. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_mcp_vault_validate.py +0 -0
  251. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_multicall.py +0 -0
  252. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_oracle.py +0 -0
  253. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_oracle_mapping.py +0 -0
  254. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_plasma_vault.py +0 -0
  255. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_public_type_reachability.py +0 -0
  256. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_reader_encoding.py +0 -0
  257. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_readiness_selection.py +0 -0
  258. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_revert_decoding.py +0 -0
  259. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_rewards_manager.py +0 -0
  260. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_roles.py +0 -0
  261. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_sdk_layering.py +0 -0
  262. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  263. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  264. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  265. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_crosschain_canary.py +0 -0
  266. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_crosschain_hypercore.py +0 -0
  267. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  268. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  269. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  270. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  271. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  272. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  273. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  274. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_examples_arbitrum.py +0 -0
  275. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_examples_base.py +0 -0
  276. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_examples_crosschain.py +0 -0
  277. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_external_state_executor_base.py +0 -0
  278. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  279. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  280. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  281. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_morpho_blue.py +0 -0
  282. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_pilot_v3.py +0 -0
  283. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  284. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  285. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  286. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  287. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_readers_integration.py +0 -0
  288. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_release_funds.py +0 -0
  289. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_swap_on_base.py +0 -0
  290. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  291. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_simulation_observation.py +0 -0
  292. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_solidity_compiler.py +0 -0
  293. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_solidity_mirrors.py +0 -0
  294. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_substrates.py +0 -0
  295. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_types_and_events.py +0 -0
  296. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_unpriceable_tokens.py +0 -0
  297. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_vault_data_block.py +0 -0
  298. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_vault_dep_graph.py +0 -0
  299. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_vault_info_onchain_base.py +0 -0
  300. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  301. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_web3_context.py +0 -0
  302. {ipor_fusion-4.0.0.dev159 → ipor_fusion-4.0.0.dev162}/tests/test_withdraw_manager.py +0 -0
  303. {ipor_fusion-4.0.0.dev159 → 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
 
@@ -838,6 +865,22 @@ that only some entries carry is `NotRequired` (a balance fuse's `pct_of_total` a
838
865
  These apply to every caller, type-checked or not. Changes described in full above
839
866
  are listed with a link.
840
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
+
841
884
  - **Vault reads are pinned to one block**: every read of `fetch_vault_data`, log
842
885
  scans included, runs at the resolved block; see
843
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.dev159
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.dev159"
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,
@@ -649,6 +651,8 @@ __all__ = [
649
651
  "MULTICALL3_ADDRESS",
650
652
  "VaultSimulator",
651
653
  "StateOverrideProvider",
654
+ "AccountOverride",
655
+ "BlockOverrides",
652
656
  "SimulationObservation",
653
657
  "SimulationResult",
654
658
  "SimulatedCallResult",
@@ -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
@@ -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(
@@ -2,7 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  from collections.abc import Callable, Mapping
4
4
  from dataclasses import dataclass, field
5
- from typing import Any, Generic, TypeVar
5
+ from typing import Final, Generic, NotRequired, TypedDict, TypeVar, Unpack
6
6
 
7
7
  from eth_abi import decode, encode
8
8
  from eth_abi.exceptions import DecodingError
@@ -10,7 +10,7 @@ from eth_typing import ChecksumAddress
10
10
  from eth_utils import keccak
11
11
  from hexbytes import HexBytes
12
12
  from web3 import Web3
13
- from web3.types import BlockIdentifier, Nonce, RPCEndpoint, Timestamp
13
+ from web3.types import BlockIdentifier, Nonce, RPCEndpoint, Timestamp, TxParams
14
14
  from web3.utils.address import get_create_address
15
15
 
16
16
  from ipor_fusion.core.contract import Call, _encode_calldata
@@ -27,12 +27,78 @@ from ipor_fusion.types import PlasmaVaultAddress
27
27
  T = TypeVar("T")
28
28
  T_co = TypeVar("T_co", covariant=True)
29
29
 
30
+
31
+ class AccountOverride(TypedDict, total=False):
32
+ """One account's ``eth_simulateV1`` state override, sent as given:
33
+ quantities and code are ``0x`` hex strings, storage maps a ``0x`` slot to a
34
+ ``0x`` word. ``state`` replaces the account's storage, ``stateDiff``
35
+ patches it."""
36
+
37
+ balance: str
38
+ nonce: str
39
+ code: str
40
+ state: Mapping[str, str]
41
+ stateDiff: Mapping[str, str]
42
+ movePrecompileToAddress: str
43
+
44
+
45
+ class BlockOverrides(TypedDict, total=False):
46
+ """``eth_simulateV1`` block overrides; an ``int`` is sent as ``0x`` hex."""
47
+
48
+ number: int | str
49
+ time: int | str
50
+ gasLimit: int | str
51
+ feeRecipient: str
52
+ prevRandao: str
53
+ baseFeePerGas: int | str
54
+ blobBaseFee: int | str
55
+
56
+
30
57
  #: ``n`` (the sent block's index in the run) -> account overrides for it.
31
- StateOverrideProvider = Callable[[int], Mapping[str, Mapping[str, Any]]]
58
+ StateOverrideProvider = Callable[[int], Mapping[str, AccountOverride]]
59
+
60
+
61
+ class _AccessListEntry(TypedDict):
62
+ address: ChecksumAddress
63
+ storageKeys: list[str]
64
+
65
+
66
+ # One entry of a block's ``calls``; functional syntax because ``from`` is a
67
+ # keyword. ``to`` is absent for a contract creation.
68
+ _SimulatedCall = TypedDict(
69
+ "_SimulatedCall",
70
+ {
71
+ "from": NotRequired[ChecksumAddress],
72
+ "to": NotRequired[ChecksumAddress],
73
+ "input": str,
74
+ "nonce": NotRequired[str],
75
+ "gas": NotRequired[str],
76
+ "value": NotRequired[str],
77
+ "chainId": NotRequired[str],
78
+ "type": NotRequired[str],
79
+ "gasPrice": NotRequired[str],
80
+ "maxFeePerGas": NotRequired[str],
81
+ "maxPriorityFeePerGas": NotRequired[str],
82
+ "accessList": NotRequired[list[_AccessListEntry]],
83
+ },
84
+ )
85
+
86
+
87
+ class _BlockStateCall(TypedDict):
88
+ calls: list[_SimulatedCall]
89
+ blockOverrides: dict[str, str]
90
+ stateOverrides: NotRequired[dict[str, AccountOverride]]
91
+
92
+
93
+ class _SimulateRequest(TypedDict):
94
+ blockStateCalls: list[_BlockStateCall]
95
+ validation: bool
96
+ traceTransfers: bool
97
+
32
98
 
33
99
  DEFAULT_BLOCK_TIME_INCREMENT = 12
34
100
 
35
- _TRANSACTION_QUANTITIES = (
101
+ _TRANSACTION_QUANTITIES: Final = (
36
102
  "nonce",
37
103
  "gas",
38
104
  "value",
@@ -64,15 +130,15 @@ class _Call:
64
130
  gas: int | None = None
65
131
  predicted_address: ChecksumAddress | None = None
66
132
  # A complete serialized transaction (`add_transaction`), sent as is.
67
- transaction: dict[str, Any] | None = None
133
+ transaction: _SimulatedCall | None = None
68
134
  observation: SimulationObservation[object] | None = None
69
135
 
70
136
 
71
137
  @dataclass(slots=True)
72
138
  class _Block:
73
139
  calls: list[_Call] = field(default_factory=list)
74
- block_overrides: dict[str, Any] = field(default_factory=dict)
75
- state_overrides: dict[str, dict[str, Any]] = field(default_factory=dict)
140
+ block_overrides: dict[str, str] = field(default_factory=dict)
141
+ state_overrides: dict[str, AccountOverride] = field(default_factory=dict)
76
142
  override_provider: StateOverrideProvider | None = None
77
143
 
78
144
 
@@ -297,15 +363,21 @@ class VaultSimulator:
297
363
  self._current.block_overrides["time"] = hex(self._baseline() + int(seconds))
298
364
  return self
299
365
 
300
- def with_block_override(self, **fields: Any) -> VaultSimulator:
366
+ def with_block_override(self, **fields: Unpack[BlockOverrides]) -> VaultSimulator:
367
+ """Set block overrides on the current block, in the order given."""
301
368
  for key, value in fields.items():
302
- self._current.block_overrides[key] = (
303
- hex(value) if isinstance(value, int) else value
304
- )
369
+ if isinstance(value, int):
370
+ value = hex(value)
371
+ elif not isinstance(value, str):
372
+ raise TypeError(
373
+ f"block override {key} must be an int or a hex string, "
374
+ f"got {type(value).__name__}"
375
+ )
376
+ self._current.block_overrides[key] = value
305
377
  return self
306
378
 
307
379
  def with_state_override(
308
- self, address: ChecksumAddress, **overrides: Any
380
+ self, address: ChecksumAddress, **overrides: Unpack[AccountOverride]
309
381
  ) -> VaultSimulator:
310
382
  """Merge an account override into the current block.
311
383
 
@@ -313,9 +385,9 @@ class VaultSimulator:
313
385
  a later ``stateDiff`` patches it. One call cannot contain both forms.
314
386
  """
315
387
  checksum_address = Web3.to_checksum_address(address)
316
- current = self._current.state_overrides.get(checksum_address, {})
388
+ current = self._current.state_overrides.get(checksum_address)
317
389
  self._current.state_overrides[checksum_address] = _compose_account_overrides(
318
- current, overrides
390
+ current or AccountOverride(), overrides
319
391
  )
320
392
  return self
321
393
 
@@ -455,7 +527,7 @@ class VaultSimulator:
455
527
  return self
456
528
 
457
529
  def add_transaction(
458
- self, transaction: Mapping[str, Any], label: str | None = None
530
+ self, transaction: TxParams, label: str | None = None
459
531
  ) -> VaultSimulator:
460
532
  """Queue a complete transaction dict exactly as a signer would receive it,
461
533
  e.g. the output of `Call.build_transaction` or `Web3Context.build_transaction`.
@@ -465,7 +537,8 @@ class VaultSimulator:
465
537
  signed rather than a call rebuilt from its calldata. With
466
538
  ``validation=True`` the node also checks nonce, fees and balance. The
467
539
  result counts toward ``success`` and ``gas_used`` like `execute`. An
468
- unknown key raises instead of being dropped.
540
+ unknown key raises instead of being dropped. The calldata may come as
541
+ ``input`` instead of ``data``.
469
542
  """
470
543
  unknown = set(transaction) - _TRANSACTION_KEYS
471
544
  if unknown:
@@ -474,7 +547,7 @@ class VaultSimulator:
474
547
  raise ValueError("transaction cannot carry both data and input")
475
548
  if not transaction.get("from") or not transaction.get("to"):
476
549
  raise ValueError("transaction requires from and to")
477
- data = HexBytes(transaction.get("data", transaction.get("input", b"")))
550
+ data = HexBytes(_transaction_data(transaction))
478
551
  serialized = _serialize_transaction(transaction, data)
479
552
  self._current.calls.append(
480
553
  _Call(
@@ -562,12 +635,12 @@ class VaultSimulator:
562
635
  if not non_empty_blocks:
563
636
  raise ValueError("No calls buffered — call execute() or observe() first")
564
637
 
565
- block_state_calls: list[dict[str, Any]] = []
638
+ block_state_calls: list[_BlockStateCall] = []
566
639
  # A block with no calls is not sent, but its overrides still apply to
567
640
  # everything after it (state carries between blocks), so they fold
568
641
  # into the next block that is sent; that block's own values win.
569
- block_overrides: dict[str, Any] = {}
570
- state_overrides: dict[str, dict[str, Any]] = {}
642
+ block_overrides: dict[str, str] = {}
643
+ state_overrides: dict[str, AccountOverride] = {}
571
644
  modeled_time = self._baseline()
572
645
  previous_sent_time = modeled_time
573
646
  provider: StateOverrideProvider | None = None
@@ -591,21 +664,22 @@ class VaultSimulator:
591
664
  if modeled_time <= previous_sent_time:
592
665
  raise ValueError("simulated block times must be strictly increasing")
593
666
  previous_sent_time = modeled_time
594
- entry: dict[str, Any] = {
595
- "calls": [self._serialize_call(c) for c in block.calls]
667
+ entry: _BlockStateCall = {
668
+ "calls": [self._serialize_call(c) for c in block.calls],
669
+ "blockOverrides": block_overrides,
596
670
  }
597
- entry["blockOverrides"] = block_overrides
598
671
  if state_overrides:
599
672
  entry["stateOverrides"] = state_overrides
600
673
  block_state_calls.append(entry)
601
674
  block_overrides, state_overrides = {}, {}
602
675
 
676
+ request: _SimulateRequest = {
677
+ "blockStateCalls": block_state_calls,
678
+ "validation": self._validation,
679
+ "traceTransfers": self._trace_transfers,
680
+ }
603
681
  payload = [
604
- {
605
- "blockStateCalls": block_state_calls,
606
- "validation": self._validation,
607
- "traceTransfers": self._trace_transfers,
608
- },
682
+ request,
609
683
  self._block if isinstance(self._block, str) else hex(int(self._block)),
610
684
  ]
611
685
 
@@ -618,10 +692,10 @@ class VaultSimulator:
618
692
 
619
693
  return self._parse_response(response["result"])
620
694
 
621
- def _serialize_call(self, call: _Call) -> dict[str, Any]:
695
+ def _serialize_call(self, call: _Call) -> _SimulatedCall:
622
696
  if call.transaction is not None:
623
- return dict(call.transaction)
624
- out: dict[str, Any] = {"input": "0x" + call.data.hex()}
697
+ return call.transaction.copy()
698
+ out: _SimulatedCall = {"input": "0x" + call.data.hex()}
625
699
  if call.to is not None:
626
700
  out["to"] = call.to
627
701
  if call.from_:
@@ -699,10 +773,20 @@ class VaultSimulator:
699
773
  )
700
774
 
701
775
 
702
- def _serialize_transaction(
703
- transaction: Mapping[str, Any], data: HexBytes
704
- ) -> dict[str, Any]:
705
- out: dict[str, Any] = {
776
+ def _transaction_data(transaction: TxParams) -> bytes | bytearray | str:
777
+ """The calldata under ``data``, or under ``input``, which `TxParams` does
778
+ not name but a node-shaped transaction carries."""
779
+ if "data" in transaction:
780
+ return transaction["data"]
781
+ fields: Mapping[str, object] = transaction
782
+ data = fields.get("input", b"")
783
+ if not isinstance(data, bytes | bytearray | str):
784
+ raise TypeError(f"transaction input must be bytes or hex, got {data!r}")
785
+ return data
786
+
787
+
788
+ def _serialize_transaction(transaction: TxParams, data: HexBytes) -> _SimulatedCall:
789
+ out: _SimulatedCall = {
706
790
  "from": Web3.to_checksum_address(transaction["from"]),
707
791
  "to": Web3.to_checksum_address(transaction["to"]),
708
792
  "input": data.to_0x_hex(),
@@ -723,7 +807,7 @@ def _serialize_transaction(
723
807
 
724
808
 
725
809
  def _apply_override_provider(
726
- overrides: dict[str, dict[str, Any]],
810
+ overrides: dict[str, AccountOverride],
727
811
  provider: StateOverrideProvider | None,
728
812
  sent_block: int,
729
813
  ) -> None:
@@ -732,18 +816,18 @@ def _apply_override_provider(
732
816
  return
733
817
  for address, fields in provider(sent_block).items():
734
818
  overrides[address] = _compose_account_overrides(
735
- dict(fields), overrides.get(address, {})
819
+ AccountOverride(**fields), overrides.get(address) or AccountOverride()
736
820
  )
737
821
 
738
822
 
739
823
  def _compose_account_overrides(
740
- earlier: dict[str, Any], later: dict[str, Any]
741
- ) -> dict[str, Any]:
824
+ earlier: AccountOverride, later: AccountOverride
825
+ ) -> AccountOverride:
742
826
  for fields in (earlier, later):
743
827
  if "state" in fields and "stateDiff" in fields:
744
828
  raise ValueError("account override cannot contain both state and stateDiff")
745
829
 
746
- merged = {**earlier, **later}
830
+ merged: AccountOverride = {**earlier, **later}
747
831
  if "state" in later:
748
832
  merged["state"] = dict(later["state"])
749
833
  merged.pop("stateDiff", None)