ipor-fusion 4.0.0.dev303__tar.gz → 4.0.0.dev311__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 (362) hide show
  1. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/AGENTS.md +5 -0
  2. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/PKG-INFO +8 -6
  3. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/README.md +7 -5
  4. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/pyproject.toml +1 -1
  5. ipor_fusion-4.0.0.dev311/scripts/fusion_error_signatures.py +137 -0
  6. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/__init__.py +4 -0
  7. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/__init__.py +4 -0
  8. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/access.py +104 -1
  9. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/errors.py +4 -0
  10. ipor_fusion-4.0.0.dev311/src/ipor_fusion/fusion_errors.py +1437 -0
  11. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_access_manager.py +98 -0
  12. ipor_fusion-4.0.0.dev311/tests/test_fusion_errors.py +122 -0
  13. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_public_api.py +4 -0
  14. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_claim_merkl_wrapper_base.py +3 -1
  15. ipor_fusion-4.0.0.dev311/tests/test_simulate_timelock_base.py +51 -0
  16. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.claude-plugin/marketplace.json +0 -0
  17. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.claude-plugin/plugin.json +0 -0
  18. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.env.example +0 -0
  19. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.gemini/settings.json +0 -0
  20. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.git-blame-ignore-revs +0 -0
  21. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.github/workflows/cd.yml +0 -0
  22. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.github/workflows/ci.yml +0 -0
  23. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.github/workflows/commit-lint.yml +0 -0
  24. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.github/workflows/notify-slack.yml +0 -0
  25. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.github/workflows/python-build.yml +0 -0
  26. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.github/workflows/python-publish.yml +0 -0
  27. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.github/workflows/release.yml +0 -0
  28. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.github/workflows/report-slack.yml +0 -0
  29. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.gitignore +0 -0
  30. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.mcp.json +0 -0
  31. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.pre-commit-config.yaml +0 -0
  32. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/.python-version +0 -0
  33. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/CHANGELOG.md +0 -0
  34. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/CLAUDE.md +0 -0
  35. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/CODEOWNERS +0 -0
  36. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/LICENSE +0 -0
  37. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/MIGRATION_4.md +0 -0
  38. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/build.sh +0 -0
  39. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/examples/CONTRIBUTING.md +0 -0
  40. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/examples/README.md +0 -0
  41. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  42. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  43. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  44. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  45. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/examples/external_state_margin_leg_base.py +0 -0
  46. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/examples/simple_aave_v3_supply_base.py +0 -0
  47. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/pytest.ini +0 -0
  48. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/scripts/commit-check.sh +0 -0
  49. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/scripts/crosschain_readiness.py +0 -0
  50. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/skills/ipor-deploy-vault/SKILL.md +0 -0
  51. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/about.py +0 -0
  52. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cache.py +0 -0
  53. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/chains.py +0 -0
  54. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/__init__.py +0 -0
  55. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/address_cmd.py +0 -0
  56. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  57. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/config_cmd.py +0 -0
  58. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/config_store.py +0 -0
  59. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/main.py +0 -0
  60. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/market_cmd.py +0 -0
  61. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/options.py +0 -0
  62. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  63. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/preflight_cmd.py +0 -0
  64. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  65. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/vault_health.py +0 -0
  66. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/vault_info_view.py +0 -0
  67. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  68. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  69. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/config/__init__.py +0 -0
  70. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/config/roles.py +0 -0
  71. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/address.py +0 -0
  72. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/context.py +0 -0
  73. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/context_manager.py +0 -0
  74. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/contract.py +0 -0
  75. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/erc20.py +0 -0
  76. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/external_state_executor.py +0 -0
  77. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/fee_manager.py +0 -0
  78. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/fuse.py +0 -0
  79. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/fuse_action.py +0 -0
  80. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/fuse_decoding.py +0 -0
  81. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/fusion_factory.py +0 -0
  82. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/logs.py +0 -0
  83. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/multicall.py +0 -0
  84. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/oracle.py +0 -0
  85. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/plasma_vault.py +0 -0
  86. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/rewards_manager.py +0 -0
  87. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/simulation.py +0 -0
  88. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/simulation_result.py +0 -0
  89. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  90. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/__init__.py +0 -0
  91. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  92. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  93. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  94. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  95. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  96. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  97. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  98. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  99. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  100. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/contracts.py +0 -0
  101. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/discovery.py +0 -0
  102. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/errors.py +0 -0
  103. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  104. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  105. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  106. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  107. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/lane.py +0 -0
  108. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/logs.py +0 -0
  109. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/messages.py +0 -0
  110. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/simulation.py +0 -0
  111. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  112. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  113. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  114. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  115. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  116. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/crosschain/transport.py +0 -0
  117. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/dependency_graph.py +0 -0
  118. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/entry_cli.py +0 -0
  119. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/entry_mcp.py +0 -0
  120. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/explorer.py +0 -0
  121. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/field_docs.py +0 -0
  122. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/__init__.py +0 -0
  123. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  124. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/async_action.py +0 -0
  125. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/base.py +0 -0
  126. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  127. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/erc4626.py +0 -0
  128. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  129. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/events.py +0 -0
  130. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/external_state.py +0 -0
  131. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
  132. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  133. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  134. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/hypercore.py +0 -0
  135. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
  136. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/merkl.py +0 -0
  137. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/morpho.py +0 -0
  138. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  139. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  140. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/fuses/universal.py +0 -0
  141. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/guide/__init__.py +0 -0
  142. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/guide/architecture.md +0 -0
  143. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/guide/glossary.md +0 -0
  144. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/guide/invariants.md +0 -0
  145. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/guide/quickstart.md +0 -0
  146. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/hypercore/__init__.py +0 -0
  147. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/market_ids.py +0 -0
  148. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/market_info.py +0 -0
  149. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/mcp/__init__.py +0 -0
  150. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/mcp/guide.py +0 -0
  151. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/mcp/models.py +0 -0
  152. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/mcp/server.py +0 -0
  153. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/morpho_api.py +0 -0
  154. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/preflight.py +0 -0
  155. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/py.typed +0 -0
  156. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/__init__.py +0 -0
  157. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/aave_v3.py +0 -0
  158. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/aave_v4.py +0 -0
  159. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/compound_v3.py +0 -0
  160. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/hypercore.py +0 -0
  161. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  162. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/lending_health.py +0 -0
  163. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/morpho.py +0 -0
  164. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  165. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
  166. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  167. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/position_manager.py +0 -0
  168. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  169. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  170. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/readers/unpriceable.py +0 -0
  171. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/registry.py +0 -0
  172. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/substrates.py +0 -0
  173. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/types.py +0 -0
  174. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/validation.py +0 -0
  175. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/vault_data.py +0 -0
  176. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/vault_erc20.py +0 -0
  177. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/vault_info.py +0 -0
  178. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/vault_managers.py +0 -0
  179. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/vault_positions.py +0 -0
  180. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/src/ipor_fusion/vault_reads.py +0 -0
  181. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/UniswapV3UniversalRouter.py +0 -0
  182. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_crosschain.py +0 -0
  183. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_crosschain_lifecycle.py +0 -0
  184. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_crosschain_recovery.py +0 -0
  185. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_euler_v2.py +0 -0
  186. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_event_args.py +0 -0
  187. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_fake_rpc.py +0 -0
  188. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_foundry.py +0 -0
  189. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_golden.py +0 -0
  190. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_guide.py +0 -0
  191. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_hypercore_model.py +0 -0
  192. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_hypercore_shadow.py +0 -0
  193. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_live.py +0 -0
  194. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_multicall.py +0 -0
  195. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_oracle_mapping_fake.py +0 -0
  196. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_simulate.py +0 -0
  197. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/_validation.py +0 -0
  198. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/addresses.py +0 -0
  199. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/conftest.py +0 -0
  200. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/constants.py +0 -0
  201. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  202. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/hypercore_market55.json +0 -0
  203. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/hypercore_official.json +0 -0
  204. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
  205. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
  206. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
  207. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
  208. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
  209. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
  210. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
  211. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
  212. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_blue.json +0 -0
  213. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
  214. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
  215. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
  216. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
  217. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
  218. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
  219. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
  220. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/simulate_v1_request.json +0 -0
  221. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/clean.json +0 -0
  222. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
  223. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  224. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
  225. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
  226. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
  227. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
  228. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/fetched.json +0 -0
  229. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
  230. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/full.json +0 -0
  231. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
  232. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/full.txt +0 -0
  233. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/rich.json +0 -0
  234. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
  235. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  236. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_about.py +0 -0
  237. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cache.py +0 -0
  238. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_chains.py +0 -0
  239. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_address.py +0 -0
  240. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_changelog.py +0 -0
  241. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_commands.py +0 -0
  242. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_config_store.py +0 -0
  243. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_helpers.py +0 -0
  244. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_hypercore.py +0 -0
  245. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_lending_health.py +0 -0
  246. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_market_golden.py +0 -0
  247. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_market_morpho_blue.py +0 -0
  248. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_mcp_parity.py +0 -0
  249. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_oracle_mapping.py +0 -0
  250. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_oracle_mapping_golden.py +0 -0
  251. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_pending_requests_scan.py +0 -0
  252. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_preflight.py +0 -0
  253. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_role_accounts.py +0 -0
  254. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_vault_info_golden.py +0 -0
  255. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_vault_predates_getters.py +0 -0
  256. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_cli_vault_validate.py +0 -0
  257. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_contract_call.py +0 -0
  258. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_contract_encoder.py +0 -0
  259. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_ccip_events.py +0 -0
  260. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_ccip_indexer.py +0 -0
  261. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_ccip_quote.py +0 -0
  262. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_chainlink.py +0 -0
  263. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_contracts.py +0 -0
  264. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_encoding.py +0 -0
  265. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_errors.py +0 -0
  266. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_lane.py +0 -0
  267. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_layering.py +0 -0
  268. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_readiness.py +0 -0
  269. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_readiness_report.py +0 -0
  270. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_crosschain_transport.py +0 -0
  271. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_docs_typing.py +0 -0
  272. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_erc20.py +0 -0
  273. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_error_hierarchy.py +0 -0
  274. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_examples_composed_hypercore.py +0 -0
  275. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_examples_crosschain.py +0 -0
  276. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  277. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_examples_vaults.py +0 -0
  278. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_explorer.py +0 -0
  279. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_external_state_events.py +0 -0
  280. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_external_state_executor.py +0 -0
  281. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_fee_manager.py +0 -0
  282. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_fuse_decoding.py +0 -0
  283. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_fuse_encoding.py +0 -0
  284. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_fusion_instance.py +0 -0
  285. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_governance_wrappers.py +0 -0
  286. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_guide.py +0 -0
  287. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_hypercore_deployment.py +0 -0
  288. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_hypercore_events.py +0 -0
  289. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_hypercore_flow.py +0 -0
  290. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_hypercore_live.py +0 -0
  291. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_hypercore_outcome.py +0 -0
  292. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_hypercore_readers.py +0 -0
  293. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_hypercore_simulation.py +0 -0
  294. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_logs.py +0 -0
  295. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_mcp_address.py +0 -0
  296. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_mcp_hypercore.py +0 -0
  297. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_mcp_models.py +0 -0
  298. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_mcp_preflight.py +0 -0
  299. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_mcp_server.py +0 -0
  300. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_mcp_vault_validate.py +0 -0
  301. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_multicall.py +0 -0
  302. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_oracle.py +0 -0
  303. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_oracle_mapping.py +0 -0
  304. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_plasma_vault.py +0 -0
  305. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_preflight.py +0 -0
  306. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_public_type_reachability.py +0 -0
  307. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_reader_encoding.py +0 -0
  308. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_readiness_selection.py +0 -0
  309. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_registry.py +0 -0
  310. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_revert_decoding.py +0 -0
  311. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_rewards_manager.py +0 -0
  312. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_roles.py +0 -0
  313. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_sdk_layering.py +0 -0
  314. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  315. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  316. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_crosschain_canary.py +0 -0
  317. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_crosschain_hypercore.py +0 -0
  318. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  319. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  320. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  321. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  322. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  323. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  324. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  325. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_examples_arbitrum.py +0 -0
  326. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_examples_base.py +0 -0
  327. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_examples_crosschain.py +0 -0
  328. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_external_state_executor_base.py +0 -0
  329. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  330. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  331. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  332. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_morpho_blue.py +0 -0
  333. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_pilot_v3.py +0 -0
  334. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  335. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  336. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  337. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  338. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_preflight_base.py +0 -0
  339. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_readers_integration.py +0 -0
  340. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_release_funds.py +0 -0
  341. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_swap_on_base.py +0 -0
  342. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  343. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulation_errors.py +0 -0
  344. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_simulation_observation.py +0 -0
  345. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_solidity_compiler.py +0 -0
  346. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_solidity_mirrors.py +0 -0
  347. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_substrates.py +0 -0
  348. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_types_and_events.py +0 -0
  349. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_unpriceable_tokens.py +0 -0
  350. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_validation.py +0 -0
  351. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_vault_data_block.py +0 -0
  352. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_vault_dep_graph.py +0 -0
  353. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_vault_info_fetched_golden.py +0 -0
  354. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_vault_info_onchain_base.py +0 -0
  355. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  356. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_vault_reconciliation_onchain_base.py +0 -0
  357. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_vault_simulator_blocks.py +0 -0
  358. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_web3_context.py +0 -0
  359. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/test_withdraw_manager.py +0 -0
  360. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/typed_client/consumer.py +0 -0
  361. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/tests/typed_client/rejected.py +0 -0
  362. {ipor_fusion-4.0.0.dev303 → ipor_fusion-4.0.0.dev311}/uv.lock +0 -0
@@ -237,6 +237,11 @@ the lifecycle matrix follows that.
237
237
 
238
238
  - `chains.py` chain registry; `market_ids.py` `IporFusionMarkets`; `types.py`; `errors.py`
239
239
  defines every SDK exception class (`tests/test_error_hierarchy.py` pins it)
240
+ - `fusion_errors.py` — `FUSION_ERROR_SIGNATURES`, every custom error of the
241
+ ipor-fusion contracts and their imports, registered by `errors.py` so reverts
242
+ decode by name; generated, never edited by hand: `uv run python
243
+ scripts/fusion_error_signatures.py ../ipor-fusion --source <commit>` (needs the
244
+ checkout's `npm ci`)
240
245
  - `about.py` — package version, repository URL, CHANGELOG parsing (`fusion changelog`,
241
246
  `server_info`); `field_docs.py` — `DOCS`, the JSON field descriptions shared by CLI
242
247
  output and MCP models
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev303
3
+ Version: 4.0.0.dev311
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
@@ -369,10 +369,12 @@ A flash-loan fuse also needs `update_callback_handler(handler, sender, selector)
369
369
 
370
370
  The full clone → configure → deposit → execute sequence is exercised in [`tests/test_simulate_vault_from_scratch_base.py`](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/tests/test_simulate_vault_from_scratch_base.py).
371
371
 
372
- Custom errors of the crosschain contracts decode by name: importing
373
- `ipor_fusion.crosschain` registers their signatures (`CROSSCHAIN_ERROR_SIGNATURES`),
374
- so a simulated or sent call that reverts reads `NavSettledStale(8453)` in
375
- `SimulationResult.revert_reason` and `TransactionError` instead of a bare selector.
372
+ Custom errors of the IPOR Fusion contracts and the libraries they import
373
+ (OpenZeppelin included) decode by name, so a simulated or sent call that reverts
374
+ reads `AccessManagedUnauthorized(0x...)`, `UnsupportedFuse()` or
375
+ `NavSettledStale(8453)` in `SimulationResult.revert_reason` and `TransactionError`
376
+ instead of a bare selector. Importing `ipor_fusion.crosschain` also registers
377
+ `CROSSCHAIN_ERROR_SIGNATURES`.
376
378
  `register_custom_errors([...])` adds your own, and `SimulationResult.raise_for_failure()`
377
379
  raises `SimulationError` naming the first failed call.
378
380
 
@@ -476,7 +478,7 @@ Fuse.method() --> FuseAction --> PlasmaVault.execute([actions]) --> Call
476
478
  | `PlasmaVault` | ERC-4626 vault — execute, deposit, withdraw, previews, fuse, market, fee and limit configuration |
477
479
  | `VaultSimulator` | Batch `execute` + reads through `eth_simulateV1`, multi-block, no local node |
478
480
  | `FusionFactory` | Deploy a new vault (`clone`, `clone_supervised`) |
479
- | `AccessManager` | Role-based access control |
481
+ | `AccessManager` | Role-based access control; `read_call_plan(ctx, call, caller=)` says whether a restricted call goes now, must be scheduled (execution delay), waits, is ready or is forbidden, and gives the call to send now; `schedule`, `execute` and `cancel` build the timelock calls |
480
482
  | `RewardsManager` | Claim and vest rewards |
481
483
  | `WithdrawManager` | Time-windowed withdrawal requests |
482
484
  | `FeeManager` | Deposit, performance, and management fee configuration and harvesting |
@@ -320,10 +320,12 @@ A flash-loan fuse also needs `update_callback_handler(handler, sender, selector)
320
320
 
321
321
  The full clone → configure → deposit → execute sequence is exercised in [`tests/test_simulate_vault_from_scratch_base.py`](https://github.com/IPOR-Labs/ipor-fusion.py/blob/main/tests/test_simulate_vault_from_scratch_base.py).
322
322
 
323
- Custom errors of the crosschain contracts decode by name: importing
324
- `ipor_fusion.crosschain` registers their signatures (`CROSSCHAIN_ERROR_SIGNATURES`),
325
- so a simulated or sent call that reverts reads `NavSettledStale(8453)` in
326
- `SimulationResult.revert_reason` and `TransactionError` instead of a bare selector.
323
+ Custom errors of the IPOR Fusion contracts and the libraries they import
324
+ (OpenZeppelin included) decode by name, so a simulated or sent call that reverts
325
+ reads `AccessManagedUnauthorized(0x...)`, `UnsupportedFuse()` or
326
+ `NavSettledStale(8453)` in `SimulationResult.revert_reason` and `TransactionError`
327
+ instead of a bare selector. Importing `ipor_fusion.crosschain` also registers
328
+ `CROSSCHAIN_ERROR_SIGNATURES`.
327
329
  `register_custom_errors([...])` adds your own, and `SimulationResult.raise_for_failure()`
328
330
  raises `SimulationError` naming the first failed call.
329
331
 
@@ -427,7 +429,7 @@ Fuse.method() --> FuseAction --> PlasmaVault.execute([actions]) --> Call
427
429
  | `PlasmaVault` | ERC-4626 vault — execute, deposit, withdraw, previews, fuse, market, fee and limit configuration |
428
430
  | `VaultSimulator` | Batch `execute` + reads through `eth_simulateV1`, multi-block, no local node |
429
431
  | `FusionFactory` | Deploy a new vault (`clone`, `clone_supervised`) |
430
- | `AccessManager` | Role-based access control |
432
+ | `AccessManager` | Role-based access control; `read_call_plan(ctx, call, caller=)` says whether a restricted call goes now, must be scheduled (execution delay), waits, is ready or is forbidden, and gives the call to send now; `schedule`, `execute` and `cancel` build the timelock calls |
431
433
  | `RewardsManager` | Claim and vest rewards |
432
434
  | `WithdrawManager` | Time-windowed withdrawal requests |
433
435
  | `FeeManager` | Deposit, performance, and management fee configuration and harvesting |
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.0.0.dev303"
3
+ version = "4.0.0.dev311"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/env python3
2
+ """Regenerate ``src/ipor_fusion/fusion_errors.py`` from an ipor-fusion checkout.
3
+
4
+ Collects every ``error`` declaration of the Solidity files reachable by import
5
+ from ``contracts/`` (the contracts and the libraries they import, OpenZeppelin
6
+ included, resolved through the checkout's ``foundry.toml`` remappings) and
7
+ writes them as
8
+ canonical ``Name(type,...)`` signatures: enums become ``uint8``, contract,
9
+ interface and library types ``address``, ``uint``/``int`` their 256-bit form.
10
+ Any other parameter type (a struct, a user-defined value type) stops the run,
11
+ because its canonical form needs the compiler.
12
+
13
+ uv run python scripts/fusion_error_signatures.py ../ipor-fusion --source <commit>
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import argparse
19
+ import re
20
+ import sys
21
+ import tomllib
22
+ from pathlib import Path
23
+
24
+ _OUTPUT = Path(__file__).resolve().parent.parent / "src/ipor_fusion/fusion_errors.py"
25
+ _IMPORT = re.compile(r'^\s*import\s+(?:[^"\']*\s+from\s+)?["\']([^"\']+)["\']', re.M)
26
+ _ERROR = re.compile(r"\berror\s+(\w+)\s*\(([^)]*)\)\s*;")
27
+ _ENUM = re.compile(r"\benum\s+(\w+)")
28
+ _CONTRACT = re.compile(r"\b(?:abstract\s+)?(?:contract|interface|library)\s+(\w+)")
29
+ _ELEMENTARY = re.compile(
30
+ r"^(address|bool|string|bytes([1-9]|[12]\d|3[0-2])?|u?int(8|16|24|32|40|48|56|64"
31
+ r"|72|80|88|96|104|112|120|128|136|144|152|160|168|176|184|192|200|208|216|224"
32
+ r"|232|240|248|256)?)$"
33
+ )
34
+ _COMMENTS = re.compile(r"//[^\n]*|/\*.*?\*/", re.S)
35
+
36
+
37
+ class _Resolver:
38
+ """Forge's import resolution: relative paths, then the longest matching
39
+ remapping, then the checkout root and each ``libs`` directory."""
40
+
41
+ def __init__(self, root: Path) -> None:
42
+ profile = tomllib.loads((root / "foundry.toml").read_text())["profile"]
43
+ default = profile["default"]
44
+ pairs = [entry.split("=", 1) for entry in default["remappings"]]
45
+ self._root = root
46
+ self._remappings = sorted(pairs, key=lambda pair: -len(pair[0]))
47
+ self._bases = [root, *(root / lib for lib in default["libs"])]
48
+
49
+ def __call__(self, spec: str, importer: Path) -> Path:
50
+ if spec.startswith("."):
51
+ return (importer.parent / spec).resolve()
52
+ for prefix, target in self._remappings:
53
+ if spec.startswith(prefix):
54
+ return (self._root / (target + spec.removeprefix(prefix))).resolve()
55
+ for base in self._bases:
56
+ if (base / spec).is_file():
57
+ return (base / spec).resolve()
58
+ return (self._root / spec).resolve()
59
+
60
+
61
+ def _closure(root: Path) -> dict[Path, str]:
62
+ resolve = _Resolver(root)
63
+ pending = sorted((root / "contracts").rglob("*.sol"))
64
+ sources: dict[Path, str] = {}
65
+ while pending:
66
+ path = pending.pop()
67
+ if path in sources:
68
+ continue
69
+ if not path.is_file():
70
+ raise SystemExit(f"unresolved import: {path}")
71
+ text = _COMMENTS.sub("", path.read_text())
72
+ sources[path] = text
73
+ pending.extend(resolve(spec, path) for spec in _IMPORT.findall(text))
74
+ return sources
75
+
76
+
77
+ def _canonical(param: str, enums: set[str], contracts: set[str], where: str) -> str:
78
+ kind = param.split()[0].split(".")[-1]
79
+ if kind in ("uint", "int"):
80
+ return f"{kind}256"
81
+ if _ELEMENTARY.fullmatch(kind):
82
+ return kind
83
+ if kind in enums:
84
+ return "uint8"
85
+ if kind in contracts:
86
+ return "address"
87
+ raise SystemExit(f"{where}: no canonical form for parameter type {kind!r}")
88
+
89
+
90
+ def collect(root: Path) -> list[str]:
91
+ sources = _closure(root)
92
+ enums = {name for text in sources.values() for name in _ENUM.findall(text)}
93
+ contracts = {name for text in sources.values() for name in _CONTRACT.findall(text)}
94
+ signatures: set[str] = set()
95
+ for path, text in sources.items():
96
+ for name, params in _ERROR.findall(text):
97
+ types = [
98
+ _canonical(p.strip(), enums, contracts, f"{path}: {name}")
99
+ for p in params.split(",")
100
+ if p.strip()
101
+ ]
102
+ signatures.add(f"{name}({','.join(types)})")
103
+ return sorted(signatures)
104
+
105
+
106
+ def render(signatures: list[str], source: str) -> str:
107
+ lines = "\n".join(f' "{signature}",' for signature in signatures)
108
+ return f'''"""Custom errors of the IPOR Fusion contracts and the libraries they import
109
+ (OpenZeppelin included), registered by :mod:`ipor_fusion.errors` so revert data
110
+ decodes by name (``AccessManagedUnauthorized(0x...)``, ``UnsupportedFuse()``)
111
+ instead of a bare selector.
112
+
113
+ Generated by ``scripts/fusion_error_signatures.py`` from ipor-fusion {source};
114
+ do not edit by hand.
115
+ """
116
+
117
+ #: ``Name(type,...)`` signatures, sorted; the selector is the keccak of each.
118
+ FUSION_ERROR_SIGNATURES: tuple[str, ...] = (
119
+ {lines}
120
+ )
121
+ '''
122
+
123
+
124
+ def main() -> None:
125
+ parser = argparse.ArgumentParser(description="Regenerate fusion_errors.py.")
126
+ parser.add_argument("checkout", type=Path, help="ipor-fusion checkout")
127
+ parser.add_argument(
128
+ "--source", required=True, help="what the checkout is, e.g. a commit"
129
+ )
130
+ args = parser.parse_args()
131
+ signatures = collect(args.checkout.resolve())
132
+ _OUTPUT.write_text(render(signatures, args.source))
133
+ print(f"{len(signatures)} signatures -> {_OUTPUT}", file=sys.stderr)
134
+
135
+
136
+ if __name__ == "__main__":
137
+ main()
@@ -27,6 +27,8 @@ from ipor_fusion.config.roles import Roles
27
27
  from ipor_fusion.core.access import (
28
28
  AccessManager,
29
29
  CallPermission,
30
+ CallPlan,
31
+ CallPlanKind,
30
32
  RoleAccount,
31
33
  RoleAccountJson,
32
34
  RoleAccountsJson,
@@ -556,6 +558,8 @@ __all__ = [
556
558
  "RoleAccount",
557
559
  "RoleAccountJson",
558
560
  "CallPermission",
561
+ "CallPlan",
562
+ "CallPlanKind",
559
563
  "RoleStatus",
560
564
  "resolve_access_manager",
561
565
  "role_account_sort_key",
@@ -1,6 +1,8 @@
1
1
  from ipor_fusion.core.access import (
2
2
  AccessManager,
3
3
  CallPermission,
4
+ CallPlan,
5
+ CallPlanKind,
4
6
  RoleAccount,
5
7
  RoleAccountJson,
6
8
  RoleAccountsJson,
@@ -107,6 +109,8 @@ __all__ = [
107
109
  "RoleAccount",
108
110
  "RoleAccountJson",
109
111
  "CallPermission",
112
+ "CallPlan",
113
+ "CallPlanKind",
110
114
  "RoleStatus",
111
115
  "RewardsManager",
112
116
  "VestingData",
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Callable, Sequence
2
2
  from dataclasses import dataclass
3
- from typing import TypedDict
3
+ from typing import Literal, TypedDict
4
4
 
5
5
  from eth_abi import decode, encode
6
6
  from eth_abi.exceptions import InsufficientDataBytes
@@ -68,6 +68,33 @@ class CallPermission:
68
68
  return self.immediate or self.delay > 0
69
69
 
70
70
 
71
+ # schedule(when=0): as soon as the sender's execution delay allows.
72
+ _ASAP = Timestamp(0)
73
+
74
+ CallPlanKind = Literal["immediate", "schedule", "waiting", "ready", "forbidden"]
75
+
76
+
77
+ @dataclass(frozen=True, slots=True)
78
+ class CallPlan:
79
+ """How ``caller`` gets a restricted call through the access manager now.
80
+
81
+ - ``immediate``: send the call itself (``next_call``).
82
+ - ``schedule``: the caller has an execution delay and nothing is scheduled;
83
+ ``next_call`` schedules it, executable ``delay`` seconds after it lands.
84
+ - ``waiting``: scheduled, executable at ``scheduled_at``; nothing to send yet.
85
+ - ``ready``: scheduled and executable; ``next_call`` is the call itself (or
86
+ the manager's ``execute`` with ``via_manager``), valid until the schedule
87
+ expires a week after ``scheduled_at``; an expired one plans ``schedule``.
88
+ - ``forbidden``: the caller has no role for it, or the target is closed.
89
+ """
90
+
91
+ kind: CallPlanKind
92
+ permission: CallPermission
93
+ operation: ScheduleId
94
+ scheduled_at: Timestamp | None
95
+ next_call: Call[None] | None
96
+
97
+
71
98
  def _call_permission_decoder(values: tuple[bool, int]) -> CallPermission:
72
99
  immediate, delay = values
73
100
  return CallPermission(immediate=immediate, delay=Period(delay))
@@ -204,6 +231,82 @@ class AccessManager(ContractWrapper):
204
231
  Web3.keccak(encode(["address", "address", "bytes"], [caller, target, data]))
205
232
  )
206
233
 
234
+ def schedule(
235
+ self, target: ChecksumAddress, data: bytes, when: Timestamp = _ASAP
236
+ ) -> Call[None]:
237
+ """Schedule ``data`` on ``target`` for the sender, executable at ``when``;
238
+ 0 means as soon as the sender's execution delay allows, and a nonzero
239
+ time before that reverts."""
240
+ return self._write("schedule(address,bytes,uint48)", target, data, when)
241
+
242
+ def execute(self, target: ChecksumAddress, data: bytes) -> Call[None]:
243
+ """Run ``data`` on ``target`` through the manager: an immediate call, or
244
+ the sender's scheduled operation once it is executable (it is consumed)."""
245
+ return self._write("execute(address,bytes)", target, data)
246
+
247
+ def cancel(
248
+ self, caller: ChecksumAddress, target: ChecksumAddress, data: bytes
249
+ ) -> Call[None]:
250
+ """Cancel ``caller``'s scheduled ``data`` on ``target``: the caller itself,
251
+ an ADMIN_ROLE member, or the guardian of the role ``target`` maps the
252
+ function's selector to may."""
253
+ return self._write("cancel(address,address,bytes)", caller, target, data)
254
+
255
+ def read_call_plan(
256
+ self,
257
+ ctx: Web3Context,
258
+ call: Call[object],
259
+ *,
260
+ caller: ChecksumAddress,
261
+ via_manager: bool = False,
262
+ ) -> CallPlan:
263
+ """What ``caller`` sends now to get ``call`` executed: an access and
264
+ timelock plan from ``canCall`` and, for a delayed caller, the schedule of
265
+ exactly ``call``'s calldata, all read at the block ``ctx.default_block``
266
+ names (a number, hash or tag, resolved once). It does not run the target's own checks
267
+ (redemption lock, pre-hooks, balances): simulate the call for those.
268
+
269
+ A ready operation is sent as ``call`` itself, from ``caller``: the target
270
+ consumes the schedule and still sees ``caller`` as the sender, which
271
+ deposits, withdrawals and other sender-dependent calls need.
272
+ ``via_manager`` sends it through the manager's ``execute`` instead, for a
273
+ target that does not consume schedules; the manager is then the sender.
274
+
275
+ Raises ``ValueError`` for a call on the access manager itself: its
276
+ authorization is function-specific (role grants depend on the role's
277
+ admin, target configuration on the target's admin delay, and the IPOR
278
+ manager's own restricted functions on ``canCall``), which this plan does
279
+ not model.
280
+ """
281
+ if call.to == self.address:
282
+ raise ValueError(
283
+ "read_call_plan does not plan calls on the access manager itself:"
284
+ " their authorization is function-specific"
285
+ )
286
+ block = ctx.web3.eth.get_block(ctx.default_block)
287
+ ctx = ctx.at_block(block["number"])
288
+ selector = bytes(call.data[:4])
289
+ permission = self.can_call(caller, call.to, selector).call(ctx)
290
+ operation = self.hash_operation(caller, call.to, call.data)
291
+ direct = Call[None](to=call.to, data=call.data)
292
+ if permission.immediate:
293
+ return CallPlan("immediate", permission, operation, None, direct)
294
+ if permission.delay == 0:
295
+ return CallPlan("forbidden", permission, operation, None, None)
296
+ scheduled_at = self.get_schedule(operation).call(ctx)
297
+ if scheduled_at == 0:
298
+ return CallPlan(
299
+ "schedule",
300
+ permission,
301
+ operation,
302
+ None,
303
+ self.schedule(call.to, call.data),
304
+ )
305
+ if scheduled_at > block["timestamp"]:
306
+ return CallPlan("waiting", permission, operation, scheduled_at, None)
307
+ ready = self.execute(call.to, call.data) if via_manager else direct
308
+ return CallPlan("ready", permission, operation, scheduled_at, ready)
309
+
207
310
  def can_call(
208
311
  self, caller: ChecksumAddress, target: ChecksumAddress, selector: bytes
209
312
  ) -> Call[CallPermission]:
@@ -10,6 +10,7 @@ from eth_utils import function_signature_to_4byte_selector
10
10
  from web3 import Web3
11
11
  from web3.types import TxParams, TxReceipt
12
12
 
13
+ from ipor_fusion.fusion_errors import FUSION_ERROR_SIGNATURES
13
14
  from ipor_fusion.types import TxHash
14
15
 
15
16
  log = logging.getLogger(__name__)
@@ -50,6 +51,9 @@ def register_custom_errors(signatures: Iterable[str]) -> None:
50
51
  CUSTOM_ERRORS[function_signature_to_4byte_selector(canonical)] = (name, types)
51
52
 
52
53
 
54
+ register_custom_errors(FUSION_ERROR_SIGNATURES)
55
+
56
+
53
57
  def decode_custom_error(selector: bytes, payload: bytes) -> str | None:
54
58
  """``Name(arg, arg)`` for a registered selector, ``None`` otherwise."""
55
59
  registered = CUSTOM_ERRORS.get(bytes(selector))