ipor-fusion 4.0.0.dev66__tar.gz → 4.0.0.dev71__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 (292) hide show
  1. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/MIGRATION_4.md +18 -0
  2. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/PKG-INFO +1 -1
  3. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/pyproject.toml +1 -1
  4. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/__init__.py +2 -0
  5. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/market_cmd.py +1 -1
  6. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/options.py +2 -2
  7. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/vault_info_view.py +4 -4
  8. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/context.py +16 -17
  9. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/contract.py +3 -3
  10. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/fusion_factory.py +64 -1
  11. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/logs.py +13 -3
  12. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/simulation.py +15 -12
  13. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/quote.py +1 -3
  14. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/simulation.py +2 -6
  15. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/stargate/contracts.py +16 -9
  16. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/stargate/layerzero.py +10 -10
  17. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/stargate/transport.py +7 -4
  18. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/errors.py +3 -3
  19. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/explorer.py +1 -1
  20. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/base.py +5 -1
  21. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/crosschain/ccip.py +4 -4
  22. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/crosschain/stargate.py +4 -3
  23. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/universal.py +5 -1
  24. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/aave_v3.py +2 -4
  25. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/morpho.py +9 -3
  26. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/oracle_mapping_nodes.py +1 -3
  27. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/oracle_mapping_reader.py +2 -2
  28. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/types.py +3 -1
  29. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/vault_info.py +1 -1
  30. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_encoding.py +3 -1
  31. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_external_state_executor.py +1 -1
  32. ipor_fusion-4.0.0.dev71/tests/test_fusion_instance.py +70 -0
  33. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_crosschain_hyperevm.py +1 -3
  34. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_vault_simulator_blocks.py +11 -0
  35. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_web3_context.py +1 -1
  36. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/typed_client/consumer.py +8 -0
  37. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.claude-plugin/marketplace.json +0 -0
  38. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.claude-plugin/plugin.json +0 -0
  39. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.env.example +0 -0
  40. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.gemini/settings.json +0 -0
  41. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.git-blame-ignore-revs +0 -0
  42. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.github/workflows/cd.yml +0 -0
  43. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.github/workflows/ci.yml +0 -0
  44. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.github/workflows/commit-lint.yml +0 -0
  45. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.github/workflows/notify-slack.yml +0 -0
  46. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.github/workflows/python-build.yml +0 -0
  47. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.github/workflows/python-publish.yml +0 -0
  48. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.github/workflows/release.yml +0 -0
  49. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.github/workflows/report-slack.yml +0 -0
  50. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.gitignore +0 -0
  51. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.mcp.json +0 -0
  52. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.pre-commit-config.yaml +0 -0
  53. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/.python-version +0 -0
  54. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/AGENTS.md +0 -0
  55. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/CHANGELOG.md +0 -0
  56. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/CLAUDE.md +0 -0
  57. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/CODEOWNERS +0 -0
  58. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/LICENSE +0 -0
  59. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/README.md +0 -0
  60. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/build.sh +0 -0
  61. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/examples/CONTRIBUTING.md +0 -0
  62. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/examples/README.md +0 -0
  63. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  64. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  65. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  66. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  67. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/examples/external_state_margin_leg_base.py +0 -0
  68. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/examples/simple_aave_v3_supply_base.py +0 -0
  69. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/pytest.ini +0 -0
  70. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/scripts/commit-check.sh +0 -0
  71. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/scripts/crosschain_readiness.py +0 -0
  72. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/skills/ipor-deploy-vault/SKILL.md +0 -0
  73. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/about.py +0 -0
  74. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cache.py +0 -0
  75. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/chains.py +0 -0
  76. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/__init__.py +0 -0
  77. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  78. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/config_cmd.py +0 -0
  79. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/config_store.py +0 -0
  80. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/main.py +0 -0
  81. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  82. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  83. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/vault_health.py +0 -0
  84. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
  85. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  86. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/config/__init__.py +0 -0
  87. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/config/roles.py +0 -0
  88. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/__init__.py +0 -0
  89. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/access.py +0 -0
  90. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/address.py +0 -0
  91. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/erc20.py +0 -0
  92. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/external_state_executor.py +0 -0
  93. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/fee_manager.py +0 -0
  94. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/fuse_action.py +0 -0
  95. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/multicall.py +0 -0
  96. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/oracle.py +0 -0
  97. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/plasma_vault.py +0 -0
  98. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/rewards_manager.py +0 -0
  99. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  100. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/__init__.py +0 -0
  101. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  102. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  103. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  104. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  105. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  106. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  107. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  108. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  109. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/contracts.py +0 -0
  110. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/discovery.py +0 -0
  111. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/errors.py +0 -0
  112. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/lane.py +0 -0
  113. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/logs.py +0 -0
  114. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/messages.py +0 -0
  115. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  116. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  117. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/crosschain/transport.py +0 -0
  118. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/dependency_graph.py +0 -0
  119. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/entry_cli.py +0 -0
  120. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/entry_mcp.py +0 -0
  121. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/field_docs.py +0 -0
  122. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/__init__.py +0 -0
  123. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  124. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/async_action.py +0 -0
  125. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  126. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/crosschain/__init__.py +0 -0
  127. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/crosschain/base.py +0 -0
  128. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/erc4626.py +0 -0
  129. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  130. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/events.py +0 -0
  131. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/external_state.py +0 -0
  132. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/external_state_events.py +0 -0
  133. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  134. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  135. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/hypercore.py +0 -0
  136. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
  137. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/merkl.py +0 -0
  138. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/morpho.py +0 -0
  139. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  140. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  141. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/guide/__init__.py +0 -0
  142. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/guide/architecture.md +0 -0
  143. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/guide/glossary.md +0 -0
  144. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/guide/invariants.md +0 -0
  145. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/guide/quickstart.md +0 -0
  146. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/market_ids.py +0 -0
  147. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/market_info.py +0 -0
  148. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/mcp/__init__.py +0 -0
  149. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/mcp/guide.py +0 -0
  150. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/mcp/models.py +0 -0
  151. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/mcp/server.py +0 -0
  152. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/morpho_api.py +0 -0
  153. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/py.typed +0 -0
  154. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/__init__.py +0 -0
  155. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/aave_v4.py +0 -0
  156. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/compound_v3.py +0 -0
  157. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/hypercore.py +0 -0
  158. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  159. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/lending_health.py +0 -0
  160. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  161. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/position_manager.py +0 -0
  162. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  163. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  164. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/readers/unpriceable.py +0 -0
  165. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/substrates.py +0 -0
  166. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/validation.py +0 -0
  167. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/vault_data.py +0 -0
  168. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/vault_managers.py +0 -0
  169. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/vault_positions.py +0 -0
  170. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/src/ipor_fusion/vault_reads.py +0 -0
  171. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/UniswapV3UniversalRouter.py +0 -0
  172. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_crosschain.py +0 -0
  173. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_crosschain_lifecycle.py +0 -0
  174. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_crosschain_recovery.py +0 -0
  175. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_euler_v2.py +0 -0
  176. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_foundry.py +0 -0
  177. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_guide.py +0 -0
  178. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_hypercore_model.py +0 -0
  179. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_hypercore_shadow.py +0 -0
  180. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_multicall.py +0 -0
  181. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_simulate.py +0 -0
  182. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/_validation.py +0 -0
  183. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/addresses.py +0 -0
  184. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/conftest.py +0 -0
  185. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/constants.py +0 -0
  186. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  187. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/fixtures/hypercore_market55.json +0 -0
  188. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/fixtures/vault_info_golden/clean.json +0 -0
  189. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/fixtures/vault_info_golden/clean.txt +0 -0
  190. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/fixtures/vault_info_golden/rich.json +0 -0
  191. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  192. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_about.py +0 -0
  193. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_access_manager.py +0 -0
  194. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cache.py +0 -0
  195. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_chains.py +0 -0
  196. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_changelog.py +0 -0
  197. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_commands.py +0 -0
  198. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_config_store.py +0 -0
  199. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_helpers.py +0 -0
  200. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_hypercore.py +0 -0
  201. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_lending_health.py +0 -0
  202. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_market_morpho_blue.py +0 -0
  203. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_oracle_mapping.py +0 -0
  204. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_pending_requests_scan.py +0 -0
  205. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_role_accounts.py +0 -0
  206. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_vault_info_golden.py +0 -0
  207. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_vault_predates_getters.py +0 -0
  208. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_cli_vault_validate.py +0 -0
  209. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_contract_call.py +0 -0
  210. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_contract_encoder.py +0 -0
  211. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_ccip_events.py +0 -0
  212. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_ccip_indexer.py +0 -0
  213. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_ccip_quote.py +0 -0
  214. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_chainlink.py +0 -0
  215. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_contracts.py +0 -0
  216. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_errors.py +0 -0
  217. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_lane.py +0 -0
  218. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_layering.py +0 -0
  219. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_readiness.py +0 -0
  220. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_readiness_report.py +0 -0
  221. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_crosschain_transport.py +0 -0
  222. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_erc20.py +0 -0
  223. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_examples_composed_hypercore.py +0 -0
  224. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_examples_crosschain.py +0 -0
  225. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  226. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_examples_vaults.py +0 -0
  227. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_explorer.py +0 -0
  228. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_external_state_events.py +0 -0
  229. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_fee_manager.py +0 -0
  230. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_fuse_encoding.py +0 -0
  231. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_guide.py +0 -0
  232. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_hypercore_deployment.py +0 -0
  233. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_hypercore_events.py +0 -0
  234. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_hypercore_flow.py +0 -0
  235. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_hypercore_live.py +0 -0
  236. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_hypercore_outcome.py +0 -0
  237. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_hypercore_readers.py +0 -0
  238. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_hypercore_simulation.py +0 -0
  239. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_logs.py +0 -0
  240. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_mcp_hypercore.py +0 -0
  241. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_mcp_models.py +0 -0
  242. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_mcp_server.py +0 -0
  243. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_mcp_vault_validate.py +0 -0
  244. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_multicall.py +0 -0
  245. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_oracle.py +0 -0
  246. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_oracle_mapping.py +0 -0
  247. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_plasma_vault.py +0 -0
  248. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_reader_encoding.py +0 -0
  249. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_readiness_selection.py +0 -0
  250. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_revert_decoding.py +0 -0
  251. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_rewards_manager.py +0 -0
  252. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_roles.py +0 -0
  253. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_sdk_layering.py +0 -0
  254. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  255. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  256. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  257. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_crosschain_canary.py +0 -0
  258. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_crosschain_hypercore.py +0 -0
  259. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  260. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  261. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  262. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  263. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  264. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  265. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_examples_arbitrum.py +0 -0
  266. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_examples_base.py +0 -0
  267. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_examples_crosschain.py +0 -0
  268. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_external_state_executor_base.py +0 -0
  269. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  270. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  271. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  272. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_morpho_blue.py +0 -0
  273. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_pilot_v3.py +0 -0
  274. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  275. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  276. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  277. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  278. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_readers_integration.py +0 -0
  279. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_release_funds.py +0 -0
  280. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_swap_on_base.py +0 -0
  281. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  282. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_solidity_compiler.py +0 -0
  283. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_solidity_mirrors.py +0 -0
  284. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_substrates.py +0 -0
  285. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_types_and_events.py +0 -0
  286. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_unpriceable_tokens.py +0 -0
  287. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_validation.py +0 -0
  288. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_vault_dep_graph.py +0 -0
  289. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_vault_info_onchain_base.py +0 -0
  290. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  291. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/tests/test_withdraw_manager.py +0 -0
  292. {ipor_fusion-4.0.0.dev66 → ipor_fusion-4.0.0.dev71}/uv.lock +0 -0
@@ -110,6 +110,24 @@ Every fuse constructor, `FuseAction.fuse`, `BalanceFuse.fuse`,
110
110
  `FusionInstance.access_manager` return one. `resolve_access_manager` still takes any
111
111
  `ChecksumAddress`: it is what checks that the address is a vault.
112
112
 
113
+ **Simulation and factory records.** `VaultSimulator(web3, *, vault=None, alpha=None,
114
+ block=...)` takes every argument after `web3` by keyword, and `vault` and `alpha` are
115
+ optional: a simulator that only observes, deploys or sends `execute_call(call,
116
+ from_=...)` needs neither, so drop a zero-address placeholder. `execute()` without
117
+ `vault` and `alpha` raises `ValueError`, as does `execute_call` without `from_` or
118
+ `alpha`. `FusionInstance.from_dict(data)` rebuilds a stored instance (the
119
+ `dataclasses.asdict` form) with every field parsed; use it instead of
120
+ `FusionInstance(**data)`, which passes raw strings into the role-typed fields.
121
+
122
+ **Transactions, LayerZero and constants.** `Web3Context.build_transaction` and
123
+ `Call.build_transaction` return web3's `TxParams` (the same keys; `data` is `0x` hex,
124
+ the fee fields are `Wei`). LayerZero endpoint ids are `LayerZeroEid`:
125
+ `StargateChain.eid`, `Packet.src_eid` / `dst_eid`, `EnforcedOptionParam.eid`,
126
+ `executor_eid()` and `eid_of()` return it and `chain_id_of`, `peers`, `lz_receive_calldata(src_eid=)`
127
+ and the Stargate fuse's `eid=` take it (`LayerZeroEid(30101)`).
128
+ `encode_oft_compose_msg(*, nonce=, src_eid=, amount_ld=, compose_msg=)` takes
129
+ keyword arguments only. `ZERO_ADDRESS` is a `ChecksumAddress` (same value).
130
+
113
131
  **Markets and substrates.** Every `IporFusionMarkets` member is a `MarketId`.
114
132
  `decode_substrate`, `market_name`, `format_market_label` take `MarketId`.
115
133
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev66
3
+ Version: 4.0.0.dev71
4
4
  Summary: The IPOR Fusion SDK for Python
5
5
  Project-URL: homepage, https://ipor.io
6
6
  Project-URL: repository, https://github.com/IPOR-Labs/ipor-fusion.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ipor-fusion"
3
- version = "4.0.0.dev66"
3
+ version = "4.0.0.dev71"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -325,6 +325,7 @@ from ipor_fusion.types import (
325
325
  HyperCoreClientOrderId,
326
326
  HyperCoreOrderId,
327
327
  HyperCoreTokenIndex,
328
+ LayerZeroEid,
328
329
  Liquidity,
329
330
  MappingStatus,
330
331
  MarginTableId,
@@ -650,6 +651,7 @@ __all__ = [
650
651
  "ProposalId",
651
652
  "ReturnRequestId",
652
653
  "StargateAssetId",
654
+ "LayerZeroEid",
653
655
  "TransferId",
654
656
  "Price",
655
657
  "Period",
@@ -51,7 +51,7 @@ class MarketIdType(click.ParamType):
51
51
 
52
52
  name = "marketId"
53
53
 
54
- def convert(self, value, param, ctx): # type: ignore[override]
54
+ def convert(self, value, param, ctx):
55
55
  if not isinstance(value, str):
56
56
  self.fail(f"expected string, got {type(value).__name__}", param, ctx)
57
57
  try:
@@ -51,7 +51,7 @@ class VaultAddressType(AddressType):
51
51
  """An address the command treats as a Plasma Vault; the command's probe
52
52
  (`resolve_access_manager`) is what checks it on chain."""
53
53
 
54
- def convert(self, value, param, ctx) -> PlasmaVaultAddress: # type: ignore[override]
54
+ def convert(self, value, param, ctx) -> PlasmaVaultAddress:
55
55
  return PlasmaVaultAddress(super().convert(value, param, ctx))
56
56
 
57
57
 
@@ -63,7 +63,7 @@ class ChainType(click.ParamType):
63
63
 
64
64
  name = "chain"
65
65
 
66
- def convert(self, value, param, ctx) -> ChainId: # type: ignore[override]
66
+ def convert(self, value, param, ctx) -> ChainId:
67
67
  if isinstance(value, int):
68
68
  return ChainId(value)
69
69
  try:
@@ -32,7 +32,7 @@ from ipor_fusion.readers.hypercore import HyperCorePendingState
32
32
  from ipor_fusion.substrates import (
33
33
  format_market_label,
34
34
  )
35
- from ipor_fusion.types import ZERO_ADDRESS, ChainId, PlasmaVaultAddress
35
+ from ipor_fusion.types import ZERO_ADDRESS, ChainId, PlasmaVaultAddress, Shares
36
36
  from ipor_fusion.validation import (
37
37
  validate_vault_state,
38
38
  )
@@ -388,16 +388,16 @@ def _print_pending_requests(data: VaultData, plasma_vault: PlasmaVault) -> None:
388
388
  click.echo(" Pending requests: (none)")
389
389
  return
390
390
 
391
- total_shares = sum((r.shares for r in requests), 0)
391
+ total_shares = Shares(sum(r.shares for r in requests))
392
392
  total_assets: int | None = _safe_call(
393
- lambda ts=total_shares: plasma_vault.convert_to_assets(ts).call() # type: ignore[misc]
393
+ lambda ts=total_shares: plasma_vault.convert_to_assets(ts).call()
394
394
  )
395
395
 
396
396
  click.echo(f" Pending requests ({len(requests)}):")
397
397
  rows: list[tuple[str, ...]] = []
398
398
  for req in requests:
399
399
  assets: int | None = _safe_call(
400
- lambda s=req.shares: plasma_vault.convert_to_assets(s).call() # type: ignore[misc]
400
+ lambda s=req.shares: plasma_vault.convert_to_assets(s).call()
401
401
  )
402
402
  assets_str = (
403
403
  f"{_format_amount(assets, data.asset_decimals)} {data.asset_symbol}"
@@ -3,7 +3,8 @@ from __future__ import annotations
3
3
  import logging
4
4
 
5
5
  from eth_account import Account
6
- from eth_typing import ChecksumAddress
6
+ from eth_typing import ChecksumAddress, HexStr
7
+ from eth_utils import encode_hex
7
8
  from hexbytes import HexBytes
8
9
  from requests import ConnectionError as RequestsConnectionError
9
10
  from requests import HTTPError, Timeout
@@ -14,7 +15,7 @@ from web3.providers.rpc.utils import (
14
15
  REQUEST_RETRY_ALLOWLIST,
15
16
  ExceptionRetryConfiguration,
16
17
  )
17
- from web3.types import BlockIdentifier, LogReceipt, TxReceipt
18
+ from web3.types import BlockIdentifier, LogReceipt, TxParams, TxReceipt, Wei
18
19
 
19
20
  from ipor_fusion.chains import GET_LOGS_RANGE_HINTS
20
21
  from ipor_fusion.core.logs import (
@@ -182,7 +183,7 @@ class Web3Context:
182
183
  data: bytes,
183
184
  *,
184
185
  block: BlockIdentifier = "latest",
185
- ) -> dict:
186
+ ) -> TxParams:
186
187
  """Build the transaction dict for ``data`` against ``to`` without signing
187
188
  or broadcasting — the same dict `send` would submit, ready to hand to an
188
189
  external signer or to inspect for a gas/cost preview (`gas` and
@@ -211,7 +212,7 @@ class Web3Context:
211
212
  max_fee_per_gas = self._calculate_max_fee_per_gas(
212
213
  gas_price, base_fee, max_priority_fee_per_gas
213
214
  )
214
- data_hex = self._data_hex(data)
215
+ data_hex = encode_hex(data)
215
216
  estimated_gas = self._estimate_gas(to, data_hex, signer, block)
216
217
  return {
217
218
  "chainId": self.chain_id,
@@ -262,7 +263,7 @@ class Web3Context:
262
263
  `build_transaction`.
263
264
  """
264
265
  signer = self._require_signer("estimate gas")
265
- return self._estimate_gas(to, self._data_hex(data), signer, block)
266
+ return self._estimate_gas(to, encode_hex(data), signer, block)
266
267
 
267
268
  def get_logs(
268
269
  self,
@@ -323,12 +324,12 @@ class Web3Context:
323
324
  def _estimate_gas(
324
325
  self,
325
326
  to: ChecksumAddress,
326
- data: str,
327
- from_address: str,
327
+ data: HexStr,
328
+ from_address: ChecksumAddress,
328
329
  block: BlockIdentifier = "latest",
329
330
  ) -> int:
330
331
  estimated = self.web3.eth.estimate_gas(
331
- {"to": to, "from": from_address, "data": data}, # type: ignore[typeddict-item]
332
+ {"to": to, "from": from_address, "data": data},
332
333
  block_identifier=block,
333
334
  )
334
335
  # State can shift between estimate and execution, so pad the limit; it is
@@ -337,25 +338,23 @@ class Web3Context:
337
338
 
338
339
  def _calculate_max_fee_per_gas(
339
340
  self, gas_price: int, base_fee: int | None, max_priority_fee_per_gas: int
340
- ) -> int:
341
+ ) -> Wei:
341
342
  # Prefer a base-fee-relative ceiling on EIP-1559 chains; fall back to a
342
343
  # gas-price margin where the block carries no base fee.
343
344
  if base_fee is None:
344
- return gas_price + self._percent_of(gas_price, self.GAS_PRICE_MARGIN)
345
- return base_fee * self.BASE_FEE_HEADROOM_MULTIPLIER + max_priority_fee_per_gas
345
+ return Wei(gas_price + self._percent_of(gas_price, self.GAS_PRICE_MARGIN))
346
+ return Wei(
347
+ base_fee * self.BASE_FEE_HEADROOM_MULTIPLIER + max_priority_fee_per_gas
348
+ )
346
349
 
347
- def _get_max_priority_fee(self, gas_price: int) -> int:
348
- return min(self.DEFAULT_TRANSACTION_MAX_PRIORITY_FEE, gas_price // 10)
350
+ def _get_max_priority_fee(self, gas_price: int) -> Wei:
351
+ return Wei(min(self.DEFAULT_TRANSACTION_MAX_PRIORITY_FEE, gas_price // 10))
349
352
 
350
353
  def _require_signer(self, action: str) -> ChecksumAddress:
351
354
  if self.signer is None:
352
355
  raise ValueError(f"Signer required to {action}")
353
356
  return self.signer
354
357
 
355
- @staticmethod
356
- def _data_hex(data: bytes) -> str:
357
- return f"0x{data.hex()}"
358
-
359
358
  @staticmethod
360
359
  def _percent_of(value: int, percentage: int) -> int:
361
360
  return value * percentage // 100
@@ -8,7 +8,7 @@ from eth_abi import decode, encode
8
8
  from eth_typing import ChecksumAddress
9
9
  from eth_utils import function_signature_to_4byte_selector
10
10
  from web3 import Web3
11
- from web3.types import BlockIdentifier, TxReceipt
11
+ from web3.types import BlockIdentifier, TxParams, TxReceipt
12
12
 
13
13
  from ipor_fusion.core.context import Web3Context
14
14
  from ipor_fusion.errors import EmptyCallResultError
@@ -105,7 +105,7 @@ class Call(Generic[T]):
105
105
 
106
106
  def build_transaction(
107
107
  self, ctx: Web3Context | None = None, *, block: BlockIdentifier = "latest"
108
- ) -> dict:
108
+ ) -> TxParams:
109
109
  """Build the transaction dict for this Call without signing or sending —
110
110
  mirrors `.send()`, delegating to `Web3Context.build_transaction`. Returns
111
111
  the dict a signer would submit; needs a signer address, no key."""
@@ -165,7 +165,7 @@ class ContractWrapper:
165
165
  and so rejects input that is genuinely the caller's.
166
166
  """
167
167
  instance = cls.__new__(cls)
168
- instance._ctx = None # type: ignore[assignment]
168
+ instance._ctx = None
169
169
  instance._address = (
170
170
  Web3.to_checksum_address(address)
171
171
  if address is not None
@@ -22,7 +22,9 @@ For external-signer flows, grab the bytes directly:
22
22
 
23
23
  from __future__ import annotations
24
24
 
25
+ from collections.abc import Callable, Mapping
25
26
  from dataclasses import dataclass
27
+ from typing import Any
26
28
 
27
29
  from eth_abi import decode as abi_decode
28
30
  from eth_typing import ChecksumAddress
@@ -31,7 +33,13 @@ from web3 import Web3
31
33
  from web3.types import TxReceipt
32
34
 
33
35
  from ipor_fusion.core.contract import Call, ContractWrapper
34
- from ipor_fusion.types import AccessManagerAddress, Period, PlasmaVaultAddress
36
+ from ipor_fusion.types import (
37
+ AccessManagerAddress,
38
+ Period,
39
+ PlasmaVaultAddress,
40
+ parse_access_manager_address,
41
+ parse_plasma_vault_address,
42
+ )
35
43
 
36
44
 
37
45
  @dataclass(slots=True, frozen=True)
@@ -70,6 +78,61 @@ class FusionInstance:
70
78
  context_manager: ChecksumAddress
71
79
  price_manager: ChecksumAddress
72
80
 
81
+ @classmethod
82
+ def from_dict(
83
+ cls, data: Mapping[str, Any]
84
+ ) -> FusionInstance: # proctor: ignore[primitives-untyped-dict]
85
+ """Rebuild an instance from its JSON form (``dataclasses.asdict``),
86
+ parsing every field: role addresses through their parsers, the rest
87
+ checksummed, integers and strings type-checked. Raises ``ValueError``
88
+ on a missing, extra or malformed field."""
89
+ missing = _INSTANCE_FIELDS.keys() - data.keys()
90
+ extra = data.keys() - _INSTANCE_FIELDS.keys()
91
+ if missing or extra:
92
+ raise ValueError(
93
+ f"FusionInstance fields: missing {sorted(missing)}, extra {sorted(extra)}"
94
+ )
95
+ return cls(
96
+ **{name: parse(data[name]) for name, parse in _INSTANCE_FIELDS.items()}
97
+ )
98
+
99
+
100
+ def _integer(value: Any) -> int:
101
+ if type(value) is not int:
102
+ raise ValueError(f"expected an integer: {value!r}")
103
+ return value
104
+
105
+
106
+ def _text(value: Any) -> str:
107
+ if not isinstance(value, str):
108
+ raise ValueError(f"expected a string: {value!r}")
109
+ return value
110
+
111
+
112
+ def _address(value: Any) -> ChecksumAddress:
113
+ return Web3.to_checksum_address(_text(value))
114
+
115
+
116
+ _INSTANCE_FIELDS: dict[str, Callable[[Any], Any]] = {
117
+ "index": _integer,
118
+ "version": _integer,
119
+ "asset_name": _text,
120
+ "asset_symbol": _text,
121
+ "asset_decimals": _integer,
122
+ "underlying_token": _address,
123
+ "underlying_token_symbol": _text,
124
+ "underlying_token_decimals": _integer,
125
+ "initial_owner": _address,
126
+ "plasma_vault": lambda value: parse_plasma_vault_address(_text(value)),
127
+ "plasma_vault_base": _address,
128
+ "access_manager": lambda value: parse_access_manager_address(_text(value)),
129
+ "fee_manager": _address,
130
+ "rewards_manager": _address,
131
+ "withdraw_manager": _address,
132
+ "context_manager": _address,
133
+ "price_manager": _address,
134
+ }
135
+
73
136
 
74
137
  _FUSION_INSTANCE_OUTPUT_TYPES: list[str] = [
75
138
  "uint256", # index
@@ -19,7 +19,9 @@ from concurrent.futures import ThreadPoolExecutor
19
19
  from typing import Protocol
20
20
 
21
21
  import requests
22
- from eth_typing import ChecksumAddress
22
+ from eth_typing import ChecksumAddress, HexStr
23
+ from eth_utils import encode_hex
24
+ from hexbytes import HexBytes
23
25
  from web3 import Web3
24
26
  from web3.exceptions import Web3Exception
25
27
  from web3.types import BlockIdentifier, FilterParams, LogReceipt
@@ -158,6 +160,14 @@ class _Rejected(Exception):
158
160
  self.size = size
159
161
 
160
162
 
163
+ def _topic_filter(topic: str | list[str]) -> HexStr | list[HexStr]:
164
+ """A topic (or an OR-list of them) as the canonical hex `eth_getLogs`
165
+ filters by; raises on text that is not hex."""
166
+ if isinstance(topic, str):
167
+ return encode_hex(HexBytes(topic))
168
+ return [encode_hex(HexBytes(alternative)) for alternative in topic]
169
+
170
+
161
171
  class _Scan:
162
172
  def __init__(
163
173
  self,
@@ -169,7 +179,7 @@ class _Scan:
169
179
  ):
170
180
  self._web3 = web3
171
181
  self._address = address
172
- self._topics = topics
182
+ self._topics = [_topic_filter(topic) for topic in topics]
173
183
  self._timeout_s = timeout_s
174
184
  self._deadline = time.monotonic() + timeout_s
175
185
  self._stopped = threading.Event()
@@ -219,7 +229,7 @@ class _Scan:
219
229
  self._check(low, high)
220
230
  params: FilterParams = {
221
231
  "address": self._address,
222
- "topics": self._topics, # type: ignore[typeddict-item]
232
+ "topics": self._topics,
223
233
  "fromBlock": low,
224
234
  "toBlock": high,
225
235
  }
@@ -16,7 +16,7 @@ from web3.utils.address import get_create_address
16
16
  from ipor_fusion.core.contract import Call, _encode_calldata
17
17
  from ipor_fusion.core.fuse_action import FuseAction
18
18
  from ipor_fusion.errors import SimulationError, decode_custom_error
19
- from ipor_fusion.types import ZERO_ADDRESS, PlasmaVaultAddress
19
+ from ipor_fusion.types import PlasmaVaultAddress
20
20
 
21
21
  #: ``n`` (the sent block's index in the run) -> account overrides for it.
22
22
  StateOverrideProvider = Callable[[int], Mapping[str, Mapping[str, Any]]]
@@ -190,15 +190,16 @@ class VaultSimulator:
190
190
  def __init__(
191
191
  self,
192
192
  web3: Web3,
193
- vault: PlasmaVaultAddress,
194
- alpha: ChecksumAddress,
193
+ *,
194
+ vault: PlasmaVaultAddress | None = None,
195
+ alpha: ChecksumAddress | None = None,
195
196
  block: BlockIdentifier = "latest",
196
197
  validation: bool = False,
197
198
  trace_transfers: bool = False,
198
199
  ):
199
200
  self._web3 = web3
200
- self._vault = Web3.to_checksum_address(vault)
201
- self._alpha = Web3.to_checksum_address(alpha)
201
+ self._vault = vault
202
+ self._alpha = alpha
202
203
  self._block: BlockIdentifier = block
203
204
  self._validation = validation
204
205
  self._trace_transfers = trace_transfers
@@ -341,6 +342,8 @@ class VaultSimulator:
341
342
 
342
343
  def execute(self, actions: list[FuseAction]) -> VaultSimulator:
343
344
  """Queue a default `execute((address,bytes)[])` batch on the vault, from alpha."""
345
+ if self._vault is None or self._alpha is None:
346
+ raise ValueError("execute needs a simulator built with vault= and alpha=")
344
347
  data = FuseAction.encode_execute_payload(actions, "execute((address,bytes)[])")
345
348
  return self._queue_execute(self._vault, data, self._alpha)
346
349
 
@@ -351,11 +354,12 @@ class VaultSimulator:
351
354
  e.g. `RewardsManager.claim_rewards(...)` where the wrapper differs from
352
355
  `PlasmaVault.execute`. `from_` defaults to alpha.
353
356
  """
354
- return self._queue_execute(
355
- call.to,
356
- call.data,
357
- Web3.to_checksum_address(from_) if from_ else self._alpha,
358
- )
357
+ sender = from_ or self._alpha
358
+ if sender is None:
359
+ raise ValueError(
360
+ "execute_call needs from_ or a simulator built with alpha="
361
+ )
362
+ return self._queue_execute(call.to, call.data, sender)
359
363
 
360
364
  def _queue_execute(
361
365
  self, to: ChecksumAddress, data: bytes, from_: ChecksumAddress
@@ -751,8 +755,7 @@ def erc20_balance_slot(
751
755
  if max_slot < 0:
752
756
  raise ValueError(no_slot)
753
757
 
754
- zero: Any = ZERO_ADDRESS
755
- sim = VaultSimulator(web3, vault=zero, alpha=zero, block=block)
758
+ sim = VaultSimulator(web3, block=block)
756
759
  for slot in range(max_slot + 1):
757
760
  holder = Web3.to_checksum_address(
758
761
  "0x" + keccak(encode(["uint256"], [slot]))[-20:].hex()
@@ -18,13 +18,11 @@ from web3.types import BlockIdentifier
18
18
 
19
19
  from ipor_fusion.core.contract import Call
20
20
  from ipor_fusion.core.simulation import VaultSimulator
21
- from ipor_fusion.types import parse_plasma_vault_address
22
21
 
23
22
  #: Selector of ``CcipInsufficientNativeFeeBalance(uint256 balance, uint256 required)``.
24
23
  INSUFFICIENT_NATIVE_FEE_SELECTOR: bytes = keccak(
25
24
  text="CcipInsufficientNativeFeeBalance(uint256,uint256)"
26
25
  )[:4]
27
- _NO_VAULT = parse_plasma_vault_address(bytes(20))
28
26
 
29
27
 
30
28
  def quote_ccip_native_fee(
@@ -45,7 +43,7 @@ def quote_ccip_native_fee(
45
43
  valid at ``block`` up to the fee check; a revert before it, or a call that
46
44
  sends no message, raises ``ValueError``.
47
45
  """
48
- simulator = VaultSimulator(web3, vault=_NO_VAULT, alpha=from_, block=block)
46
+ simulator = VaultSimulator(web3, alpha=from_, block=block)
49
47
  simulator.with_state_override(payer, balance=hex(0))
50
48
  simulator.add_call(call, from_=from_, label="quote", gas=gas)
51
49
  (result,) = simulator.run().calls
@@ -25,7 +25,6 @@ Example -- bridge from a source vault and let the dispatcher settle::
25
25
  from __future__ import annotations
26
26
 
27
27
  from collections.abc import Mapping
28
- from typing import Any
29
28
 
30
29
  from eth_typing import ChecksumAddress
31
30
  from web3 import Web3
@@ -41,7 +40,7 @@ from ipor_fusion.crosschain.transport import (
41
40
  CrosschainTransport,
42
41
  OutboundMessage,
43
42
  )
44
- from ipor_fusion.types import ZERO_ADDRESS, ChainId, PlasmaVaultAddress
43
+ from ipor_fusion.types import ChainId, PlasmaVaultAddress
45
44
 
46
45
  #: What the synthetic token source holds: enough for any test amount.
47
46
  SYNTHETIC_BALANCE = 2**96
@@ -89,10 +88,7 @@ class CrosschainSimulator:
89
88
  raise ValueError(f"chain {chain_id} is not configured on the transport")
90
89
  if chain_id in self._chains:
91
90
  raise ValueError(f"chain {chain_id} already added")
92
- zero: Any = ZERO_ADDRESS
93
- sim = VaultSimulator(
94
- web3, vault=vault or zero, alpha=alpha or zero, block=block
95
- )
91
+ sim = VaultSimulator(web3, vault=vault, alpha=alpha, block=block)
96
92
  # A chain without a real token holder to impersonate gets a synthetic
97
93
  # one, funded once by a storage override; deliveries transfer from it.
98
94
  for token in self._transport.synthetic_credit_tokens(chain_id):
@@ -23,6 +23,7 @@ from ipor_fusion.types import (
23
23
  ChainId,
24
24
  CommandId,
25
25
  DeploymentRequestId,
26
+ LayerZeroEid,
26
27
  PlasmaVaultAddress,
27
28
  PositionSetHash,
28
29
  ProposalId,
@@ -122,10 +123,12 @@ class StargateCrosschainExecutor(CrosschainExecutor):
122
123
  def proposal_count(self) -> Call[int]:
123
124
  return self._view("proposalCount()", output_types=["uint256"])
124
125
 
125
- def eid_of(self, chain_id: ChainId) -> Call[int]:
126
- return self._view("eidOf(uint256)", chain_id, output_types=["uint32"])
126
+ def eid_of(self, chain_id: ChainId) -> Call[LayerZeroEid]:
127
+ return self._view(
128
+ "eidOf(uint256)", chain_id, output_types=["uint32"], decoder=LayerZeroEid
129
+ )
127
130
 
128
- def chain_id_of(self, eid: int) -> Call[ChainId]:
131
+ def chain_id_of(self, eid: LayerZeroEid) -> Call[ChainId]:
129
132
  return self._view(
130
133
  "chainIdOf(uint32)", eid, output_types=["uint256"], decoder=ChainId
131
134
  )
@@ -252,8 +255,10 @@ class StargateCrosschainDispatcher(CrosschainDispatcher):
252
255
  def stargate_pool(self) -> Call[ChecksumAddress]:
253
256
  return self._view("STARGATE_POOL()", output_types=["address"], decoder=_address)
254
257
 
255
- def executor_eid(self) -> Call[int]:
256
- return self._view("EXECUTOR_EID()", output_types=["uint32"])
258
+ def executor_eid(self) -> Call[LayerZeroEid]:
259
+ return self._view(
260
+ "EXECUTOR_EID()", output_types=["uint32"], decoder=LayerZeroEid
261
+ )
257
262
 
258
263
  def observation(self) -> Call[Observation]:
259
264
  """``trackedIdle`` in local decimals plus ``convertToAssets`` of every
@@ -299,7 +304,7 @@ class StargateTokenMessaging(ContractWrapper):
299
304
  """Stargate V2 ``TokenMessaging``, the OApp that carries taxi packets:
300
305
  ``peers`` tells whether a route to an endpoint id exists."""
301
306
 
302
- def peers(self, eid: int) -> Call[bytes]:
307
+ def peers(self, eid: LayerZeroEid) -> Call[bytes]:
303
308
  """The peer OApp on ``eid`` as bytes32; zero when no route exists."""
304
309
  return self._view("peers(uint32)", eid, output_types=["bytes32"])
305
310
 
@@ -332,10 +337,12 @@ class StargateCrosschainFactory(CrosschainFactory):
332
337
  decoder=_address,
333
338
  )
334
339
 
335
- def eid_of(self, chain_id: ChainId) -> Call[int]:
336
- return self._view("eidOf(uint256)", chain_id, output_types=["uint32"])
340
+ def eid_of(self, chain_id: ChainId) -> Call[LayerZeroEid]:
341
+ return self._view(
342
+ "eidOf(uint256)", chain_id, output_types=["uint32"], decoder=LayerZeroEid
343
+ )
337
344
 
338
- def chain_id_of(self, eid: int) -> Call[ChainId]:
345
+ def chain_id_of(self, eid: LayerZeroEid) -> Call[ChainId]:
339
346
  return self._view(
340
347
  "chainIdOf(uint32)", eid, output_types=["uint256"], decoder=ChainId
341
348
  )
@@ -30,7 +30,7 @@ from web3 import Web3
30
30
  from ipor_fusion.core.address import _validate_not_zero_address
31
31
  from ipor_fusion.core.contract import _encode_calldata
32
32
  from ipor_fusion.crosschain.logs import log_bytes
33
- from ipor_fusion.types import ZERO_ADDRESS, MessageId, StargateAssetId
33
+ from ipor_fusion.types import ZERO_ADDRESS, LayerZeroEid, MessageId, StargateAssetId
34
34
 
35
35
  _TYPE_3 = b"\x00\x03"
36
36
  _EXECUTOR_WORKER_ID = 1
@@ -129,7 +129,7 @@ class EnforcedOptionParam:
129
129
  ``msg_type`` 1 and must carry a non-zero ``lzReceive`` gas; the compose
130
130
  (asset) lane is 2."""
131
131
 
132
- eid: int
132
+ eid: LayerZeroEid
133
133
  msg_type: int
134
134
  options: bytes | OptionsBuilder
135
135
 
@@ -149,9 +149,9 @@ class Packet:
149
149
  """One ``PacketV1Codec`` packet: the payload of a ``PacketSent`` event."""
150
150
 
151
151
  nonce: int
152
- src_eid: int
152
+ src_eid: LayerZeroEid
153
153
  sender: ChecksumAddress
154
- dst_eid: int
154
+ dst_eid: LayerZeroEid
155
155
  receiver: ChecksumAddress
156
156
  guid: MessageId
157
157
  message: bytes
@@ -162,9 +162,9 @@ class Packet:
162
162
  raise ValueError("not a version-1 LayerZero packet")
163
163
  return cls(
164
164
  nonce=int.from_bytes(encoded[1:9], "big"),
165
- src_eid=int.from_bytes(encoded[9:13], "big"),
165
+ src_eid=LayerZeroEid(int.from_bytes(encoded[9:13], "big")),
166
166
  sender=bytes32_to_address(encoded[13:45]),
167
- dst_eid=int.from_bytes(encoded[45:49], "big"),
167
+ dst_eid=LayerZeroEid(int.from_bytes(encoded[45:49], "big")),
168
168
  receiver=bytes32_to_address(encoded[49:81]),
169
169
  guid=MessageId(encoded[81:113]),
170
170
  message=encoded[113:],
@@ -213,7 +213,7 @@ class TaxiMessage:
213
213
 
214
214
 
215
215
  def encode_oft_compose_msg(
216
- nonce: int, src_eid: int, amount_ld: int, compose_msg: bytes
216
+ *, nonce: int, src_eid: LayerZeroEid, amount_ld: int, compose_msg: bytes
217
217
  ) -> bytes:
218
218
  """``OFTComposeMsgCodec.encode(nonce, srcEid, amountLD, composeMsg)``: the
219
219
  message the endpoint passes to ``lzCompose`` after a Stargate delivery.
@@ -228,12 +228,12 @@ def encode_oft_compose_msg(
228
228
 
229
229
  def lz_receive_calldata(
230
230
  *,
231
- src_eid: int,
231
+ src_eid: LayerZeroEid,
232
232
  sender: ChecksumAddress,
233
233
  nonce: int,
234
234
  guid: MessageId,
235
235
  message: bytes,
236
- executor: ChecksumAddress = ZERO_ADDRESS, # type: ignore[assignment]
236
+ executor: ChecksumAddress = ZERO_ADDRESS,
237
237
  extra_data: bytes = b"",
238
238
  ) -> bytes:
239
239
  """``lzReceive(Origin, guid, message, executor, extraData)`` as the endpoint calls it."""
@@ -252,7 +252,7 @@ def lz_compose_calldata(
252
252
  from_: ChecksumAddress,
253
253
  guid: MessageId,
254
254
  message: bytes,
255
- executor: ChecksumAddress = ZERO_ADDRESS, # type: ignore[assignment]
255
+ executor: ChecksumAddress = ZERO_ADDRESS,
256
256
  extra_data: bytes = b"",
257
257
  ) -> bytes:
258
258
  """``lzCompose(from, guid, message, executor, extraData)`` as the endpoint calls it."""
@@ -29,7 +29,7 @@ from ipor_fusion.crosschain.transport import (
29
29
  OutboundMessage,
30
30
  transfer_call,
31
31
  )
32
- from ipor_fusion.types import ChainId, StargateAssetId
32
+ from ipor_fusion.types import ChainId, LayerZeroEid, StargateAssetId
33
33
 
34
34
 
35
35
  @dataclass(frozen=True, slots=True)
@@ -45,7 +45,7 @@ class StargateChain:
45
45
  """
46
46
 
47
47
  chain_id: ChainId
48
- eid: int
48
+ eid: LayerZeroEid
49
49
  endpoint: ChecksumAddress
50
50
  token_messaging: ChecksumAddress
51
51
  stargate_pool: ChecksumAddress
@@ -87,7 +87,7 @@ class StargateTransport(CrosschainTransport):
87
87
 
88
88
  def __init__(self, chains: Iterable[StargateChain]) -> None:
89
89
  self._chains: dict[ChainId, StargateChain] = {}
90
- self._by_eid: dict[int, StargateChain] = {}
90
+ self._by_eid: dict[LayerZeroEid, StargateChain] = {}
91
91
  for chain in chains:
92
92
  if chain.chain_id in self._chains:
93
93
  raise ValueError(f"duplicate Stargate chain_id {chain.chain_id}")
@@ -194,7 +194,10 @@ class StargateTransport(CrosschainTransport):
194
194
  ]
195
195
  taxi: TaxiMessage = message.raw[1]
196
196
  compose = encode_oft_compose_msg(
197
- packet.nonce, packet.src_eid, message.token_amount, taxi.compose_msg
197
+ nonce=packet.nonce,
198
+ src_eid=packet.src_eid,
199
+ amount_ld=message.token_amount,
200
+ compose_msg=taxi.compose_msg,
198
201
  )
199
202
  return [
200
203
  transfer_call(