ipor-fusion 4.0.0.dev126__tar.gz → 4.0.0.dev129__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 (298) hide show
  1. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/MIGRATION_4.md +8 -7
  2. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/PKG-INFO +1 -1
  3. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/CONTRIBUTING.md +1 -5
  4. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/external_state_margin_leg_base.py +0 -7
  5. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/pyproject.toml +1 -1
  6. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/__init__.py +0 -2
  7. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/external_state_executor.py +20 -160
  8. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/errors.py +2 -3
  9. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_external_state_executor.py +6 -362
  10. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_public_api.py +0 -1
  11. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.claude-plugin/marketplace.json +0 -0
  12. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.claude-plugin/plugin.json +0 -0
  13. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.env.example +0 -0
  14. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.gemini/settings.json +0 -0
  15. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.git-blame-ignore-revs +0 -0
  16. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/cd.yml +0 -0
  17. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/ci.yml +0 -0
  18. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/commit-lint.yml +0 -0
  19. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/notify-slack.yml +0 -0
  20. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/python-build.yml +0 -0
  21. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/python-publish.yml +0 -0
  22. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/release.yml +0 -0
  23. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/report-slack.yml +0 -0
  24. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.gitignore +0 -0
  25. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.mcp.json +0 -0
  26. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.pre-commit-config.yaml +0 -0
  27. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.python-version +0 -0
  28. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/AGENTS.md +0 -0
  29. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/CHANGELOG.md +0 -0
  30. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/CLAUDE.md +0 -0
  31. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/CODEOWNERS +0 -0
  32. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/LICENSE +0 -0
  33. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/README.md +0 -0
  34. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/build.sh +0 -0
  35. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/README.md +0 -0
  36. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  37. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  38. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  39. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  40. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/simple_aave_v3_supply_base.py +0 -0
  41. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/pytest.ini +0 -0
  42. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/scripts/commit-check.sh +0 -0
  43. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/scripts/crosschain_readiness.py +0 -0
  44. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/skills/ipor-deploy-vault/SKILL.md +0 -0
  45. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/about.py +0 -0
  46. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cache.py +0 -0
  47. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/chains.py +0 -0
  48. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/__init__.py +0 -0
  49. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  50. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/config_cmd.py +0 -0
  51. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/config_store.py +0 -0
  52. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/main.py +0 -0
  53. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/market_cmd.py +0 -0
  54. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/options.py +0 -0
  55. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  56. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  57. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_health.py +0 -0
  58. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  59. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  60. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  61. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/config/__init__.py +0 -0
  62. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/config/roles.py +0 -0
  63. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/__init__.py +0 -0
  64. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/access.py +0 -0
  65. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/address.py +0 -0
  66. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/context.py +0 -0
  67. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/contract.py +0 -0
  68. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/erc20.py +0 -0
  69. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/fee_manager.py +0 -0
  70. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/fuse.py +0 -0
  71. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/fuse_action.py +0 -0
  72. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/fusion_factory.py +0 -0
  73. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/logs.py +0 -0
  74. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/multicall.py +0 -0
  75. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/oracle.py +0 -0
  76. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/plasma_vault.py +0 -0
  77. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/rewards_manager.py +0 -0
  78. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/simulation.py +0 -0
  79. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  80. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/__init__.py +0 -0
  81. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  82. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  83. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  84. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  85. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  86. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  87. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  88. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  89. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  90. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/contracts.py +0 -0
  91. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/discovery.py +0 -0
  92. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/errors.py +0 -0
  93. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  94. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  95. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  96. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  97. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/lane.py +0 -0
  98. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/logs.py +0 -0
  99. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/messages.py +0 -0
  100. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/simulation.py +0 -0
  101. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  102. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  103. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  104. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  105. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  106. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/transport.py +0 -0
  107. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/dependency_graph.py +0 -0
  108. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/entry_cli.py +0 -0
  109. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/entry_mcp.py +0 -0
  110. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/explorer.py +0 -0
  111. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/field_docs.py +0 -0
  112. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/__init__.py +0 -0
  113. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  114. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/async_action.py +0 -0
  115. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/base.py +0 -0
  116. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  117. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/erc4626.py +0 -0
  118. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  119. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/events.py +0 -0
  120. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/external_state.py +0 -0
  121. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/external_state_events.py +0 -0
  122. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  123. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  124. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/hypercore.py +0 -0
  125. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
  126. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/merkl.py +0 -0
  127. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/morpho.py +0 -0
  128. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  129. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  130. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/universal.py +0 -0
  131. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/__init__.py +0 -0
  132. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/architecture.md +0 -0
  133. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/glossary.md +0 -0
  134. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/invariants.md +0 -0
  135. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/quickstart.md +0 -0
  136. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/market_ids.py +0 -0
  137. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/market_info.py +0 -0
  138. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/mcp/__init__.py +0 -0
  139. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/mcp/guide.py +0 -0
  140. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/mcp/models.py +0 -0
  141. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/mcp/server.py +0 -0
  142. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/morpho_api.py +0 -0
  143. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/py.typed +0 -0
  144. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/__init__.py +0 -0
  145. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/aave_v3.py +0 -0
  146. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/aave_v4.py +0 -0
  147. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/compound_v3.py +0 -0
  148. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/hypercore.py +0 -0
  149. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  150. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/lending_health.py +0 -0
  151. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/morpho.py +0 -0
  152. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  153. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
  154. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  155. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/position_manager.py +0 -0
  156. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  157. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  158. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/unpriceable.py +0 -0
  159. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/substrates.py +0 -0
  160. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/types.py +0 -0
  161. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/validation.py +0 -0
  162. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_data.py +0 -0
  163. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_erc20.py +0 -0
  164. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_info.py +0 -0
  165. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_managers.py +0 -0
  166. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_positions.py +0 -0
  167. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_reads.py +0 -0
  168. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/UniswapV3UniversalRouter.py +0 -0
  169. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_crosschain.py +0 -0
  170. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_crosschain_lifecycle.py +0 -0
  171. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_crosschain_recovery.py +0 -0
  172. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_euler_v2.py +0 -0
  173. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_foundry.py +0 -0
  174. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_guide.py +0 -0
  175. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_hypercore_model.py +0 -0
  176. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_hypercore_shadow.py +0 -0
  177. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_multicall.py +0 -0
  178. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_simulate.py +0 -0
  179. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_validation.py +0 -0
  180. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/addresses.py +0 -0
  181. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/conftest.py +0 -0
  182. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/constants.py +0 -0
  183. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  184. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/hypercore_market55.json +0 -0
  185. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/vault_info_golden/clean.json +0 -0
  186. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  187. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/vault_info_golden/rich.json +0 -0
  188. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  189. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_about.py +0 -0
  190. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_access_manager.py +0 -0
  191. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cache.py +0 -0
  192. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_chains.py +0 -0
  193. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_changelog.py +0 -0
  194. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_commands.py +0 -0
  195. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_config_store.py +0 -0
  196. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_helpers.py +0 -0
  197. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_hypercore.py +0 -0
  198. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_lending_health.py +0 -0
  199. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_market_morpho_blue.py +0 -0
  200. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_oracle_mapping.py +0 -0
  201. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_pending_requests_scan.py +0 -0
  202. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_role_accounts.py +0 -0
  203. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_vault_info_golden.py +0 -0
  204. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_vault_predates_getters.py +0 -0
  205. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_vault_validate.py +0 -0
  206. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_contract_call.py +0 -0
  207. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_contract_encoder.py +0 -0
  208. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_ccip_events.py +0 -0
  209. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_ccip_indexer.py +0 -0
  210. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_ccip_quote.py +0 -0
  211. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_chainlink.py +0 -0
  212. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_contracts.py +0 -0
  213. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_encoding.py +0 -0
  214. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_errors.py +0 -0
  215. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_lane.py +0 -0
  216. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_layering.py +0 -0
  217. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_readiness.py +0 -0
  218. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_readiness_report.py +0 -0
  219. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_transport.py +0 -0
  220. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_erc20.py +0 -0
  221. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_error_hierarchy.py +0 -0
  222. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_examples_composed_hypercore.py +0 -0
  223. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_examples_crosschain.py +0 -0
  224. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  225. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_examples_vaults.py +0 -0
  226. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_explorer.py +0 -0
  227. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_external_state_events.py +0 -0
  228. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_fee_manager.py +0 -0
  229. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_fuse_encoding.py +0 -0
  230. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_fusion_instance.py +0 -0
  231. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_guide.py +0 -0
  232. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_deployment.py +0 -0
  233. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_events.py +0 -0
  234. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_flow.py +0 -0
  235. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_live.py +0 -0
  236. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_outcome.py +0 -0
  237. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_readers.py +0 -0
  238. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_simulation.py +0 -0
  239. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_logs.py +0 -0
  240. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_mcp_hypercore.py +0 -0
  241. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_mcp_models.py +0 -0
  242. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_mcp_server.py +0 -0
  243. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_mcp_vault_validate.py +0 -0
  244. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_multicall.py +0 -0
  245. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_oracle.py +0 -0
  246. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_oracle_mapping.py +0 -0
  247. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_plasma_vault.py +0 -0
  248. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_public_type_reachability.py +0 -0
  249. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_reader_encoding.py +0 -0
  250. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_readiness_selection.py +0 -0
  251. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_revert_decoding.py +0 -0
  252. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_rewards_manager.py +0 -0
  253. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_roles.py +0 -0
  254. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_sdk_layering.py +0 -0
  255. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  256. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  257. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  258. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_crosschain_canary.py +0 -0
  259. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_crosschain_hypercore.py +0 -0
  260. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  261. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  262. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  263. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  264. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  265. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  266. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  267. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_examples_arbitrum.py +0 -0
  268. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_examples_base.py +0 -0
  269. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_examples_crosschain.py +0 -0
  270. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_external_state_executor_base.py +0 -0
  271. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  272. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  273. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  274. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_morpho_blue.py +0 -0
  275. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_pilot_v3.py +0 -0
  276. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  277. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  278. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  279. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  280. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_readers_integration.py +0 -0
  281. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_release_funds.py +0 -0
  282. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_swap_on_base.py +0 -0
  283. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  284. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_solidity_compiler.py +0 -0
  285. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_solidity_mirrors.py +0 -0
  286. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_substrates.py +0 -0
  287. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_types_and_events.py +0 -0
  288. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_unpriceable_tokens.py +0 -0
  289. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_validation.py +0 -0
  290. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_vault_dep_graph.py +0 -0
  291. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_vault_info_onchain_base.py +0 -0
  292. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  293. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_vault_simulator_blocks.py +0 -0
  294. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_web3_context.py +0 -0
  295. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_withdraw_manager.py +0 -0
  296. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/typed_client/consumer.py +0 -0
  297. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/typed_client/rejected.py +0 -0
  298. {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/uv.lock +0 -0
@@ -255,8 +255,11 @@ before passing it on.
255
255
  `HyperCorePendingState` and `HyperCoreTransferSnapshot` carry them.
256
256
 
257
257
  **External state.** `ExternalStateExecutor.proposal_hash` returns and `confirm_balance`
258
- takes a `ProposalHash`; `BalanceProposal.proposal_hash` and `NavMark.proposal_hash`
259
- are `ProposalHash`; `ExternalStateEvent.transaction_hash` is a `TxHash`.
258
+ takes a `ProposalHash`; `BalanceProposal.proposal_hash` is a `ProposalHash`;
259
+ `ExternalStateEvent.transaction_hash` is a `TxHash`.
260
+ `ExternalStateExecutor.mark_nav` and `NavMark` are gone: send `propose_balance` and
261
+ `confirm_balance` from separate custodians, then
262
+ `PlasmaVault.update_markets_balances([IporFusionMarkets.EXTERNAL_STATE])`.
260
263
 
261
264
  **Errors and explorer.** `TransactionError(tx_hash=)` takes a `TxHash`,
262
265
  `LogScanError(address=)` a `ChecksumAddress`; `get_revert_reason` takes a `TxHash`;
@@ -349,7 +352,7 @@ placeholder wrapper.
349
352
  and `VaultSimulator.observe` stamp the same hash for the same bytes, whatever
350
353
  context executes them. Pass `ctx.chain_id` for the chain you read from.
351
354
  `pending_proposals` now refuses an executor at the zero address when the Call is
352
- built, not when it is decoded. `mark_nav` takes the chain from its contexts.
355
+ built, not when it is decoded.
353
356
 
354
357
  | 3.x | 4.0 |
355
358
  |---|---|
@@ -560,10 +563,8 @@ is the wrong one.
560
563
  `parse_balance_proposed` / `find_balance_proposed` for one of the executor's own
561
564
  `BalanceProposed` logs whose data is missing or malformed (including data that is
562
565
  not hex at all, which raised `TypeError`) or whose hash is not the hash of its own
563
- fields; and `mark_nav` when the propose receipt it fetched has no such log or
564
- records another value or proposer. A log that is not the event or not from the
565
- executor, and `find_balance_proposed` over logs that hold no match, are still
566
- `ValueError`.
566
+ fields. A log that is not the event or not from the executor, and
567
+ `find_balance_proposed` over logs that hold no match, are still `ValueError`.
567
568
  - `ccip_token_lane` raises the new `UnsupportedContractVersionError` (still a
568
569
  `ValueError`) for an OnRamp version whose layout is not verified.
569
570
  - `quote_ccip_native_fee` raises `SimulationError` (label `"quote"`, with
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev126
3
+ Version: 4.0.0.dev129
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
@@ -63,11 +63,7 @@ role-separation note is about. Label the collapse itself, not the calls: sending
63
63
  as two separate calls *is* the production shape, and only "both keys in one process" is
64
64
  simulation-only.
65
65
 
66
- Cross-reference the SDK method a production caller would use instead, where one exists -- but only
67
- where the SDK method is the one to reach for. `ExternalStateExecutor.mark_nav` is the counter-example:
68
- it composes both custodian calls, its own docstring warns that this "does not preserve the
69
- dual-custodian separation", and it is expected to be deprecated in favour of the two primitives. Do
70
- not point readers at it.
66
+ Cross-reference the SDK method a production caller would use instead, where one exists.
71
67
 
72
68
  ## 3. One self-contained file
73
69
 
@@ -894,13 +894,6 @@ def run_simulation(web3: Web3) -> SimulationResult:
894
894
  # driven from this one process. In a real deployment they live in separate
895
895
  # systems -- if one process can send both, a single compromise moves the
896
896
  # vault's NAV and the two-party design has bought nothing.
897
- #
898
- # ExternalStateExecutor.mark_nav runs the propose, the confirm and -- when
899
- # handed a vault -- the refresh in one call. It cannot be used here for a
900
- # mechanical reason: it .send(ctx)s each leg, and nothing is broadcast under
901
- # eth_simulateV1. It is also not what a production deployment wants, for the
902
- # reason above: one process holding both custodian keys is one key wearing
903
- # two hats.
904
897
  sim.next_block().with_block_time_shift(PROPOSE_OFFSET)
905
898
  sim.add_call(
906
899
  call=executor.propose_balance(VENUE_BALANCE_ACCOUNT, MARGIN_AMOUNT),
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.0.0.dev126"
3
+ version = "4.0.0.dev129"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -39,7 +39,6 @@ from ipor_fusion.core.external_state_executor import (
39
39
  BalanceProposal,
40
40
  ExternalStateExecutor,
41
41
  ExternalStateVaultState,
42
- NavMark,
43
42
  RawLog,
44
43
  read_external_state,
45
44
  )
@@ -553,7 +552,6 @@ __all__ = [
553
552
  "BalanceFuseSnapshot",
554
553
  "ExternalStateVaultState",
555
554
  "read_external_state",
556
- "NavMark",
557
555
  "CrosschainExecutor",
558
556
  "StargateCrosschainExecutor",
559
557
  "StargateCrosschainDispatcher",
@@ -6,20 +6,19 @@ by the external-state market. Its address lives in the VAULT's ERC-7201 storage
6
6
 
7
7
  NAV for the external-state market is marked by a dual-custodian propose/confirm
8
8
  on this executor, then a `update_markets_balances([EXTERNAL_STATE])` refresh on
9
- the vault. `mark_nav` runs that whole sequence in one process; a separate
10
- confirm service instead reads `pending_proposals` and confirms the hash it
11
- returns, never guessing the executor's global nonce. The same proposal reaches
12
- an offline reader through the `BalanceProposed` event -- `find_balance_proposed`
13
- picks it out of a receipt's logs, `parse_balance_proposed` decodes one row from
14
- an index -- and `balances` and `last_updated` report what the custodians last
15
- confirmed for an account.
9
+ the vault. The confirming custodian's service reads `pending_proposals` and
10
+ confirms the hash it returns, never guessing the executor's global nonce. The
11
+ same proposal reaches an offline reader through the `BalanceProposed` event --
12
+ `find_balance_proposed` picks it out of a receipt's logs,
13
+ `parse_balance_proposed` decodes one row from an index -- and `balances` and
14
+ `last_updated` report what the custodians last confirmed for an account.
16
15
  """
17
16
 
18
17
  from __future__ import annotations
19
18
 
20
19
  from collections.abc import Iterable, Mapping
21
20
  from dataclasses import dataclass, replace
22
- from typing import TYPE_CHECKING, Any
21
+ from typing import Any
23
22
 
24
23
  from eth_abi import decode, encode
25
24
  from eth_abi.exceptions import DecodingError
@@ -27,25 +26,19 @@ from eth_typing import ChecksumAddress
27
26
  from eth_utils import keccak
28
27
  from hexbytes import HexBytes
29
28
  from web3 import Web3
30
- from web3.types import BlockIdentifier, TxReceipt
29
+ from web3.types import BlockIdentifier
31
30
 
32
31
  from ipor_fusion.core.context import Web3Context
33
32
  from ipor_fusion.core.contract import Call, ContractWrapper
34
33
  from ipor_fusion.errors import ExternalStateError
35
- from ipor_fusion.market_ids import IporFusionMarkets
36
34
  from ipor_fusion.types import (
37
35
  ZERO_ADDRESS,
38
36
  Amount,
39
37
  ChainId,
40
- MarketId,
41
38
  PlasmaVaultAddress,
42
39
  ProposalHash,
43
40
  )
44
41
 
45
- if TYPE_CHECKING:
46
- from ipor_fusion.core.plasma_vault import PlasmaVault
47
-
48
-
49
42
  # The log shapes the event readers below accept: a receipt log from web3.py
50
43
  # (HexBytes fields, checksummed address), and a raw JSON-RPC or
51
44
  # `eth_simulateV1` row (0x-hex strings, lowercase address). Looser than
@@ -108,17 +101,6 @@ def _hash_of(
108
101
  )
109
102
 
110
103
 
111
- def _no_balance_proposed(
112
- executor: ChecksumAddress, balance_account: ChecksumAddress | None
113
- ) -> str:
114
- for_account = (
115
- f" for account {Web3.to_checksum_address(balance_account)}"
116
- if balance_account is not None
117
- else ""
118
- )
119
- return f"no BalanceProposed log from executor {executor}{for_account}"
120
-
121
-
122
104
  def _require_matching_hash(
123
105
  proposal: BalanceProposal, *, executor: ChecksumAddress, chain_id: ChainId
124
106
  ) -> None:
@@ -141,22 +123,6 @@ def _require_matching_hash(
141
123
  )
142
124
 
143
125
 
144
- @dataclass(frozen=True, slots=True)
145
- class NavMark:
146
- """Outcome of a `mark_nav` run: the confirmed proposal plus every receipt.
147
-
148
- `refresh_receipt` is `None` when `mark_nav` was called without a `vault`
149
- (propose + confirm only, no cached-NAV refresh).
150
- """
151
-
152
- proposed_at: int
153
- nonce: int
154
- proposal_hash: ProposalHash
155
- propose_receipt: TxReceipt
156
- confirm_receipt: TxReceipt
157
- refresh_receipt: TxReceipt | None
158
-
159
-
160
126
  @dataclass(frozen=True, slots=True)
161
127
  class ExternalStateVaultState:
162
128
  """The external-state market's vault-scoped state, read from the vault's
@@ -516,7 +482,8 @@ class ExternalStateExecutor(ContractWrapper):
516
482
  ) -> Call[None]:
517
483
  """CUSTODIAN-only: propose `value` (underlying units) as the new tracked
518
484
  balance of `balance_account`. Confirm it from a *different* custodian
519
- with `confirm_balance`; see `mark_nav` for the full sequence."""
485
+ with `confirm_balance`, then refresh the vault's cached NAV with
486
+ `PlasmaVault.update_markets_balances([EXTERNAL_STATE])`."""
520
487
  return self._write("proposeBalance(address,uint256)", balance_account, value)
521
488
 
522
489
  def confirm_balance(
@@ -743,18 +710,6 @@ class ExternalStateExecutor(ContractWrapper):
743
710
  silently skips, and over a range you filtered yourself a foreign log
744
711
  means the filter is wrong, not that the row is uninteresting.
745
712
  """
746
- found = self._last_balance_proposed(logs, balance_account, chain_id)
747
- if found is not None:
748
- return found
749
- raise ValueError(_no_balance_proposed(self._address, balance_account))
750
-
751
- def _last_balance_proposed(
752
- self,
753
- logs: Iterable[RawLog],
754
- balance_account: ChecksumAddress | None,
755
- chain_id: ChainId,
756
- ) -> BalanceProposal | None:
757
- """`find_balance_proposed` without the raise when nothing matches."""
758
713
  self._require_address()
759
714
  wanted = (
760
715
  Web3.to_checksum_address(balance_account)
@@ -770,111 +725,16 @@ class ExternalStateExecutor(ContractWrapper):
770
725
  proposal = self._decode_balance_proposed(log)
771
726
  if wanted is None or proposal.balance_account == wanted:
772
727
  found = proposal
773
- if found is not None:
774
- # Outside the loop: one hash instead of N, and only over the log
775
- # actually being returned.
776
- _require_matching_hash(
777
- found,
778
- executor=self._address,
779
- chain_id=chain_id,
780
- )
781
- return found
782
-
783
- def mark_nav(
784
- self,
785
- *,
786
- value: Amount,
787
- balance_account: ChecksumAddress,
788
- proposer_ctx: Web3Context,
789
- confirmer_ctx: Web3Context,
790
- vault: PlasmaVault | None = None,
791
- ) -> NavMark:
792
- """Mark the external-state NAV: propose `value` (custodian A), confirm it
793
- (custodian B), and optionally refresh the vault's cached NAV.
794
-
795
- `proposer_ctx` signs the propose; `confirmer_ctx` signs the confirm (and,
796
- when `vault` is given, the `update_markets_balances([EXTERNAL_STATE])`
797
- refresh). The two signers MUST be different custodians, and MUST be on
798
- the same chain; both are checked before the propose is sent, since the
799
- hash is chain-bound and a mismatch would otherwise only surface with a
800
- proposal already stranded on the proposer's chain. The confirm hash,
801
- nonce, and timestamp are taken from the propose tx's `BalanceProposed`
802
- event -- exactly what the contract stored, so no read can race the
803
- executor's global nonce. Returns a `NavMark` with the proposal and every
804
- receipt.
805
-
806
- The marked balance is valued into the vault's `totalAssets` via the
807
- external-state market (50), so it moves the share price; the refresh is
808
- what propagates the new value into the vault's cached NAV.
809
-
810
- Sends up to three transactions and blocks on each; see `NavMark`. If the
811
- propose receipt does not record the value and proposer this call sent,
812
- or carries a hash that is not the hash of those fields, it raises rather
813
- than confirming -- note the propose transaction has already landed at
814
- that point, leaving a pending proposal behind.
815
-
816
- Security: mark_nav composes `propose_balance` + `confirm_balance`, so it
817
- needs both custodian keys in one process and does not preserve the
818
- dual-custodian separation. When that separation is the point, run the two
819
- primitives from separate services instead.
820
- """
821
- proposer = proposer_ctx.signer
822
- confirmer = confirmer_ctx.signer
823
- if proposer is None:
824
- raise ValueError("proposer_ctx must have a signer")
825
- if confirmer is None:
826
- raise ValueError("confirmer_ctx must have a signer")
827
- proposer_address = Web3.to_checksum_address(proposer)
828
- if proposer_address == Web3.to_checksum_address(confirmer):
829
- raise ValueError("proposer and confirmer must be different custodians")
830
- if proposer_ctx.chain_id != confirmer_ctx.chain_id:
728
+ if found is None:
729
+ for_account = f" for account {wanted}" if wanted is not None else ""
831
730
  raise ValueError(
832
- f"proposer_ctx is on chain {proposer_ctx.chain_id} but "
833
- f"confirmer_ctx is on {confirmer_ctx.chain_id}; both custodians "
834
- "must sign on the same chain"
731
+ f"no BalanceProposed log from executor {self._address}{for_account}"
835
732
  )
836
-
837
- propose_receipt = self.propose_balance(balance_account, value).send(
838
- proposer_ctx
839
- )
840
- # Verified against the CONFIRMER's chain, which is the one the confirm
841
- # will be checked on (validated equal to the proposer's above).
842
- proposal = self._last_balance_proposed(
843
- propose_receipt["logs"], balance_account, confirmer_ctx.chain_id
844
- )
845
- if proposal is None:
846
- raise ExternalStateError(
847
- "the propose receipt records "
848
- + _no_balance_proposed(self._address, balance_account)
849
- )
850
- # The receipt is data from the node, so confirm only what we asked for:
851
- # signing off on a proposal that differs from the one just sent would
852
- # attest a value this call never chose.
853
- if proposal.value != value:
854
- raise ExternalStateError(
855
- f"proposed {value} but the receipt records {proposal.value}; "
856
- "refusing to confirm"
857
- )
858
- if proposal.proposer != proposer_address:
859
- raise ExternalStateError(
860
- f"proposal was made by {proposal.proposer}, not {proposer_address}; "
861
- "refusing to confirm"
862
- )
863
- confirm_receipt = self.confirm_balance(
864
- balance_account, proposal.proposal_hash
865
- ).send(confirmer_ctx)
866
-
867
- refresh_receipt: TxReceipt | None = None
868
- if vault is not None:
869
- refresh_receipt = vault.update_markets_balances(
870
- [MarketId(IporFusionMarkets.EXTERNAL_STATE)]
871
- ).send(confirmer_ctx)
872
-
873
- return NavMark(
874
- proposed_at=proposal.proposed_at,
875
- nonce=proposal.nonce,
876
- proposal_hash=proposal.proposal_hash,
877
- propose_receipt=propose_receipt,
878
- confirm_receipt=confirm_receipt,
879
- refresh_receipt=refresh_receipt,
733
+ # Outside the loop: one hash instead of N, and only over the log
734
+ # actually being returned.
735
+ _require_matching_hash(
736
+ found,
737
+ executor=self._address,
738
+ chain_id=chain_id,
880
739
  )
740
+ return found
@@ -212,10 +212,9 @@ class HyperCoreValuationError(IporFusionError, ValueError):
212
212
 
213
213
  class ExternalStateError(IporFusionError, ValueError):
214
214
  """The external-state market's on-chain data is not usable: the vault's
215
- storage holds no executor or a malformed word, an executor's
215
+ storage holds no executor or a malformed word, or an executor's
216
216
  ``BalanceProposed`` log is malformed or carries a hash that is not the hash
217
- of its own fields, or a propose receipt does not record the proposal that
218
- was sent.
217
+ of its own fields.
219
218
 
220
219
  Also a ValueError, the type these failures had before 4.0.
221
220
  """