ipor-fusion 4.0.0.dev108__tar.gz → 4.0.0.dev114__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 (297) hide show
  1. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/AGENTS.md +1 -1
  2. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/MIGRATION_4.md +22 -3
  3. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/PKG-INFO +1 -1
  4. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/pyproject.toml +1 -1
  5. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/vault_info_view.py +6 -8
  6. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/vault_markets_view.py +19 -26
  7. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/plasma_vault.py +11 -10
  8. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/validation.py +17 -8
  9. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/vault_data.py +34 -24
  10. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/vault_info.py +9 -7
  11. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/vault_managers.py +18 -18
  12. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/fixtures/vault_info_golden/clean.txt +1 -1
  13. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cache.py +46 -0
  14. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_commands.py +6 -18
  15. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_helpers.py +28 -52
  16. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_vault_info_golden.py +58 -17
  17. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_vault_predates_getters.py +3 -1
  18. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.claude-plugin/marketplace.json +0 -0
  19. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.claude-plugin/plugin.json +0 -0
  20. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.env.example +0 -0
  21. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.gemini/settings.json +0 -0
  22. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.git-blame-ignore-revs +0 -0
  23. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.github/workflows/cd.yml +0 -0
  24. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.github/workflows/ci.yml +0 -0
  25. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.github/workflows/commit-lint.yml +0 -0
  26. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.github/workflows/notify-slack.yml +0 -0
  27. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.github/workflows/python-build.yml +0 -0
  28. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.github/workflows/python-publish.yml +0 -0
  29. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.github/workflows/release.yml +0 -0
  30. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.github/workflows/report-slack.yml +0 -0
  31. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.gitignore +0 -0
  32. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.mcp.json +0 -0
  33. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.pre-commit-config.yaml +0 -0
  34. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/.python-version +0 -0
  35. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/CHANGELOG.md +0 -0
  36. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/CLAUDE.md +0 -0
  37. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/CODEOWNERS +0 -0
  38. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/LICENSE +0 -0
  39. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/README.md +0 -0
  40. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/build.sh +0 -0
  41. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/examples/CONTRIBUTING.md +0 -0
  42. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/examples/README.md +0 -0
  43. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/examples/advanced_euler_v2_credit_market_base.py +0 -0
  44. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
  45. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
  46. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
  47. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/examples/external_state_margin_leg_base.py +0 -0
  48. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/examples/simple_aave_v3_supply_base.py +0 -0
  49. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/pytest.ini +0 -0
  50. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/scripts/commit-check.sh +0 -0
  51. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/scripts/crosschain_readiness.py +0 -0
  52. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/skills/ipor-deploy-vault/SKILL.md +0 -0
  53. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/__init__.py +0 -0
  54. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/about.py +0 -0
  55. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cache.py +0 -0
  56. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/chains.py +0 -0
  57. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/__init__.py +0 -0
  58. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
  59. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/config_cmd.py +0 -0
  60. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/config_store.py +0 -0
  61. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/main.py +0 -0
  62. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/market_cmd.py +0 -0
  63. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/options.py +0 -0
  64. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
  65. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/vault_cmd.py +0 -0
  66. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/vault_health.py +0 -0
  67. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/cli/vault_rendering.py +0 -0
  68. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/config/__init__.py +0 -0
  69. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/config/roles.py +0 -0
  70. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/__init__.py +0 -0
  71. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/access.py +0 -0
  72. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/address.py +0 -0
  73. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/context.py +0 -0
  74. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/contract.py +0 -0
  75. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/erc20.py +0 -0
  76. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/external_state_executor.py +0 -0
  77. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/fee_manager.py +0 -0
  78. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/fuse.py +0 -0
  79. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/fuse_action.py +0 -0
  80. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/fusion_factory.py +0 -0
  81. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/logs.py +0 -0
  82. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/multicall.py +0 -0
  83. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/oracle.py +0 -0
  84. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/rewards_manager.py +0 -0
  85. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/simulation.py +0 -0
  86. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/core/withdraw_manager.py +0 -0
  87. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/__init__.py +0 -0
  88. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
  89. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
  90. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
  91. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
  92. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
  93. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
  94. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
  95. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
  96. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
  97. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/contracts.py +0 -0
  98. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/discovery.py +0 -0
  99. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/errors.py +0 -0
  100. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
  101. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
  102. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
  103. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
  104. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/lane.py +0 -0
  105. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/logs.py +0 -0
  106. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/messages.py +0 -0
  107. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/simulation.py +0 -0
  108. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
  109. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
  110. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
  111. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
  112. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
  113. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/crosschain/transport.py +0 -0
  114. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/dependency_graph.py +0 -0
  115. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/entry_cli.py +0 -0
  116. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/entry_mcp.py +0 -0
  117. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/errors.py +0 -0
  118. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/explorer.py +0 -0
  119. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/field_docs.py +0 -0
  120. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/__init__.py +0 -0
  121. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/aave_v3.py +0 -0
  122. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/async_action.py +0 -0
  123. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/base.py +0 -0
  124. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/compound_v3.py +0 -0
  125. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/erc4626.py +0 -0
  126. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/euler_v2.py +0 -0
  127. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/events.py +0 -0
  128. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/external_state.py +0 -0
  129. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/external_state_events.py +0 -0
  130. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
  131. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
  132. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/hypercore.py +0 -0
  133. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
  134. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/merkl.py +0 -0
  135. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/morpho.py +0 -0
  136. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
  137. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
  138. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/fuses/universal.py +0 -0
  139. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/guide/__init__.py +0 -0
  140. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/guide/architecture.md +0 -0
  141. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/guide/glossary.md +0 -0
  142. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/guide/invariants.md +0 -0
  143. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/guide/quickstart.md +0 -0
  144. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/market_ids.py +0 -0
  145. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/market_info.py +0 -0
  146. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/mcp/__init__.py +0 -0
  147. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/mcp/guide.py +0 -0
  148. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/mcp/models.py +0 -0
  149. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/mcp/server.py +0 -0
  150. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/morpho_api.py +0 -0
  151. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/py.typed +0 -0
  152. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/__init__.py +0 -0
  153. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/aave_v3.py +0 -0
  154. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/aave_v4.py +0 -0
  155. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/compound_v3.py +0 -0
  156. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/hypercore.py +0 -0
  157. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
  158. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/lending_health.py +0 -0
  159. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/morpho.py +0 -0
  160. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
  161. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
  162. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
  163. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/position_manager.py +0 -0
  164. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/ramses_v2.py +0 -0
  165. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
  166. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/readers/unpriceable.py +0 -0
  167. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/substrates.py +0 -0
  168. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/types.py +0 -0
  169. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/vault_erc20.py +0 -0
  170. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/vault_positions.py +0 -0
  171. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/src/ipor_fusion/vault_reads.py +0 -0
  172. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/UniswapV3UniversalRouter.py +0 -0
  173. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_crosschain.py +0 -0
  174. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_crosschain_lifecycle.py +0 -0
  175. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_crosschain_recovery.py +0 -0
  176. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_euler_v2.py +0 -0
  177. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_foundry.py +0 -0
  178. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_guide.py +0 -0
  179. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_hypercore_model.py +0 -0
  180. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_hypercore_shadow.py +0 -0
  181. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_multicall.py +0 -0
  182. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_simulate.py +0 -0
  183. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/_validation.py +0 -0
  184. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/addresses.py +0 -0
  185. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/conftest.py +0 -0
  186. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/constants.py +0 -0
  187. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/fixtures/hypercore_hip3_flow.json +0 -0
  188. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/fixtures/hypercore_market55.json +0 -0
  189. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/fixtures/vault_info_golden/clean.json +0 -0
  190. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/fixtures/vault_info_golden/rich.json +0 -0
  191. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/fixtures/vault_info_golden/rich.txt +0 -0
  192. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_about.py +0 -0
  193. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_access_manager.py +0 -0
  194. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_chains.py +0 -0
  195. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_changelog.py +0 -0
  196. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_config_store.py +0 -0
  197. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_hypercore.py +0 -0
  198. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_lending_health.py +0 -0
  199. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_market_morpho_blue.py +0 -0
  200. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_oracle_mapping.py +0 -0
  201. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_pending_requests_scan.py +0 -0
  202. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_role_accounts.py +0 -0
  203. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_cli_vault_validate.py +0 -0
  204. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_contract_call.py +0 -0
  205. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_contract_encoder.py +0 -0
  206. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_ccip_events.py +0 -0
  207. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_ccip_indexer.py +0 -0
  208. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_ccip_quote.py +0 -0
  209. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_chainlink.py +0 -0
  210. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_contracts.py +0 -0
  211. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_encoding.py +0 -0
  212. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_errors.py +0 -0
  213. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_lane.py +0 -0
  214. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_layering.py +0 -0
  215. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_readiness.py +0 -0
  216. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_readiness_report.py +0 -0
  217. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_crosschain_transport.py +0 -0
  218. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_erc20.py +0 -0
  219. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_error_hierarchy.py +0 -0
  220. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_examples_composed_hypercore.py +0 -0
  221. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_examples_crosschain.py +0 -0
  222. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_examples_euler_looping_arbitrum.py +0 -0
  223. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_examples_vaults.py +0 -0
  224. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_explorer.py +0 -0
  225. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_external_state_events.py +0 -0
  226. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_external_state_executor.py +0 -0
  227. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_fee_manager.py +0 -0
  228. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_fuse_encoding.py +0 -0
  229. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_fusion_instance.py +0 -0
  230. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_guide.py +0 -0
  231. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_hypercore_deployment.py +0 -0
  232. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_hypercore_events.py +0 -0
  233. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_hypercore_flow.py +0 -0
  234. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_hypercore_live.py +0 -0
  235. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_hypercore_outcome.py +0 -0
  236. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_hypercore_readers.py +0 -0
  237. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_hypercore_simulation.py +0 -0
  238. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_logs.py +0 -0
  239. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_mcp_hypercore.py +0 -0
  240. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_mcp_models.py +0 -0
  241. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_mcp_server.py +0 -0
  242. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_mcp_vault_validate.py +0 -0
  243. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_multicall.py +0 -0
  244. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_oracle.py +0 -0
  245. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_oracle_mapping.py +0 -0
  246. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_plasma_vault.py +0 -0
  247. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_public_api.py +0 -0
  248. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_reader_encoding.py +0 -0
  249. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_readiness_selection.py +0 -0
  250. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_revert_decoding.py +0 -0
  251. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_rewards_manager.py +0 -0
  252. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_roles.py +0 -0
  253. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_sdk_layering.py +0 -0
  254. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
  255. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
  256. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_claim_morpho_rewards.py +0 -0
  257. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_crosschain_canary.py +0 -0
  258. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_crosschain_hypercore.py +0 -0
  259. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_crosschain_hyperevm.py +0 -0
  260. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_crosschain_lifecycle.py +0 -0
  261. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_euler_v2_batch_base.py +0 -0
  262. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
  263. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
  264. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
  265. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
  266. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_examples_arbitrum.py +0 -0
  267. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_examples_base.py +0 -0
  268. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_examples_crosschain.py +0 -0
  269. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_external_state_executor_base.py +0 -0
  270. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
  271. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_looping_aave_v3_base.py +0 -0
  272. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
  273. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_morpho_blue.py +0 -0
  274. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_pilot_v3.py +0 -0
  275. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
  276. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_pilot_v5_ramses.py +0 -0
  277. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
  278. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
  279. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_readers_integration.py +0 -0
  280. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_release_funds.py +0 -0
  281. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_swap_on_base.py +0 -0
  282. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_simulate_vault_from_scratch_base.py +0 -0
  283. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_solidity_compiler.py +0 -0
  284. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_solidity_mirrors.py +0 -0
  285. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_substrates.py +0 -0
  286. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_types_and_events.py +0 -0
  287. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_unpriceable_tokens.py +0 -0
  288. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_validation.py +0 -0
  289. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_vault_dep_graph.py +0 -0
  290. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_vault_info_onchain_base.py +0 -0
  291. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
  292. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_vault_simulator_blocks.py +0 -0
  293. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_web3_context.py +0 -0
  294. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/test_withdraw_manager.py +0 -0
  295. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/typed_client/consumer.py +0 -0
  296. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/tests/typed_client/rejected.py +0 -0
  297. {ipor_fusion-4.0.0.dev108 → ipor_fusion-4.0.0.dev114}/uv.lock +0 -0
@@ -158,7 +158,7 @@ the lifecycle matrix follows that.
158
158
  subpackage (`core`, `config`, `fuses`, `readers`, `crosschain`,
159
159
  `crosschain.fuses`, `crosschain.ccip`, `crosschain.stargate`) also goes in that
160
160
  subpackage's `__all__`. `ipor_fusion.guide` keeps its own namespace. The
161
- public modules (`about`, `chains`, `dependency_graph`, `errors`, `explorer`,
161
+ public modules (`about`, `cache`, `chains`, `dependency_graph`, `errors`, `explorer`,
162
162
  `field_docs`, `market_ids`, `market_info`, `morpho_api`, `substrates`, `types`,
163
163
  `validation`, `vault_data`, `vault_info`) stay importable for the names they
164
164
  define; `cli`, `mcp` and every other module are internal. Examples, the guide
@@ -84,6 +84,20 @@ chain is always the context's:
84
84
  the context's default block and `Web3Context.get_block(block=None)` returns it,
85
85
  both instead of ``"latest"``.
86
86
 
87
+ Snapshot fields carry their units: `VaultData.total_assets`,
88
+ `underlying_balance_on_vault` and `market_balances` values are `Amount`;
89
+ `total_supply` and `supply_cap` are `Shares`; `share_decimals` / `asset_decimals` are `Decimals`;
90
+ `block_timestamp` and `deployment_timestamp` are `Timestamp`. `FeeData` fee fields
91
+ are `Fee`, `management_fee_last_update` a `Timestamp`, `unrealized_management_fee` an
92
+ `Amount`; `WithdrawManagerData.withdraw_window` is a `Period`, its fees `Fee`,
93
+ `shares_to_release` `Shares`, `last_release_funds_timestamp` a `Timestamp` and the
94
+ converted amounts `Amount`. A custom `VaultState` annotates the same.
95
+ `PlasmaVault.total_supply()`, `balance_of()` and `get_total_supply_cap()` return
96
+ `Shares` (vault shares), and `transfer` / `approve` / `transfer_from` /
97
+ `set_total_supply_cap` take `Shares`; `ERC20` keeps `Amount`. The supply cap is
98
+ now shown in share decimals labelled `shares` (``fusion vault info``) and its JSON
99
+ ``formatted`` uses `share_decimals`; it was formatted with the asset's decimals.
100
+
87
101
  `ensure_supported_chain` takes `ChainId`. `fetch_unpriceable_priced_tokens` takes the oracle and
88
102
  underlying as `ChecksumAddress`. `resolve_token_symbol`, `resolve_token_decimals`,
89
103
  `get_contract_name` and `get_deployment_tx` take `HexAddress` (a checksum address
@@ -351,8 +365,12 @@ Contract names, token symbols and decimals and deployment blocks are cached in a
351
365
  (`fetch_vault_data(metadata=True)`) and `fetch_deployment_info` use `ctx.cache`.
352
366
  `get_contract_name(chain_id, address, api_key=None, *, cache=None)` takes the cache
353
367
  explicitly (default: the file cache); pass `cache=ctx.cache` to share the
354
- context's policy. `build_vault_info_json` without `resolve_name` still names
355
- contracts from the default file cache; pass `resolve_name` to avoid it.
368
+ context's policy. The CLI's text and JSON output name contracts through the
369
+ context's cache.
370
+ - `build_vault_info_json(data)` without `resolve_name` names no contract (every
371
+ `contract` is `"?"`) instead of reading names from the on-disk cache; pass
372
+ `resolve_name=partial(get_contract_name, chain_id, api_key=..., cache=ctx.cache)`
373
+ for the CLI's document.
356
374
  - `ipor_fusion.cache` is a public module now and exports `ContractCache`,
357
375
  `FileContractCache`, `NullCache`, `CacheKey`, `CacheField`, `cache_key` and
358
376
  `default_contract_cache` (also from `ipor_fusion`). Its 3.x functions and constants
@@ -384,7 +402,8 @@ Etherscan key) and the old file can be deleted.
384
402
  - A cache never fails a read: a corrupt or unreadable file reads as empty (logged
385
403
  warning from `ipor_fusion.cache`) and is rewritten by the next write; an unwritable
386
404
  directory (read-only file system) keeps the entries in memory for the process; a
387
- custom cache that raises is treated as a miss.
405
+ custom cache that raises is treated as a miss, and so is a stored number that does
406
+ not parse.
388
407
  - `fetch_deployment_info` returns `rpc-fetch-failed` only when the creation
389
408
  transaction or its block cannot be read; a cache failure is no longer reported as
390
409
  one (the deployment block is returned).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: ipor-fusion
3
- Version: 4.0.0.dev108
3
+ Version: 4.0.0.dev114
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.dev108"
3
+ version = "4.0.0.dev114"
4
4
  description = "The IPOR Fusion SDK for Python"
5
5
  authors = [
6
6
  { name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
@@ -85,13 +85,11 @@ def _print_vault_info(
85
85
  data.deployment_error,
86
86
  ) = fetch_deployment_info(ctx, data.vault, api_key=api_key)
87
87
 
88
+ resolve_name = partial(
89
+ get_contract_name, chain_id, api_key=api_key, cache=ctx.cache
90
+ )
88
91
  if json_output:
89
- result = build_vault_info_json(
90
- data,
91
- resolve_name=partial(
92
- get_contract_name, chain_id, api_key=api_key, cache=ctx.cache
93
- ),
94
- )
92
+ result = build_vault_info_json(data, resolve_name=resolve_name)
95
93
  click.echo(json.dumps(result, indent=2))
96
94
  return
97
95
 
@@ -105,7 +103,7 @@ def _print_vault_info(
105
103
 
106
104
  _print_role_accounts(_role_accounts_json(data))
107
105
 
108
- _print_markets(data, api_key)
106
+ _print_markets(data, resolve_name)
109
107
 
110
108
  validation = validate_vault_state(data)
111
109
  click.echo("ERC20 Balances (vault holdings):")
@@ -187,7 +185,7 @@ def _print_supply(data: VaultData) -> None:
187
185
  else:
188
186
  click.echo(
189
187
  f"Supply Cap: "
190
- f"{_format_amount(data.supply_cap, data.asset_decimals)} {data.asset_symbol}"
188
+ f"{_format_amount(data.supply_cap, data.share_decimals)} shares"
191
189
  )
192
190
 
193
191
 
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from collections.abc import Sequence
3
+ from collections.abc import Callable, Sequence
4
4
  from concurrent.futures import Future, ThreadPoolExecutor
5
5
  from typing import Any
6
6
 
@@ -13,12 +13,11 @@ from ipor_fusion.cli.vault_rendering import (
13
13
  _print_table,
14
14
  _substrate_details,
15
15
  )
16
- from ipor_fusion.explorer import get_contract_name
17
16
  from ipor_fusion.substrates import (
18
17
  decode_substrate,
19
18
  format_market_label,
20
19
  )
21
- from ipor_fusion.types import ChainId, FuseAddress, MarketId, parse_hex_address
20
+ from ipor_fusion.types import FuseAddress, MarketId, parse_hex_address
22
21
  from ipor_fusion.vault_data import (
23
22
  GET_MARKET_SUBSTRATES,
24
23
  VaultData,
@@ -27,6 +26,10 @@ from ipor_fusion.vault_info import (
27
26
  _CAPABILITY_BALANCE_FUSES,
28
27
  )
29
28
 
29
+ # Address to contract name, "" when unknown (`get_contract_name` bound to the
30
+ # chain, API key and the context's cache).
31
+ NameResolver = Callable[[HexAddress], str]
32
+
30
33
 
31
34
  def _print_lending_health(data: VaultData) -> None: # noqa: C901
32
35
  lh = data.lending_health
@@ -154,16 +157,14 @@ def _print_health_lines(market: Any, indent: str) -> None:
154
157
  click.secho(f"{indent}Status: {status}", fg=color, bold=bold)
155
158
 
156
159
 
157
- def _print_markets(data: VaultData, api_key: str | None) -> None:
160
+ def _print_markets(data: VaultData, resolve_name: NameResolver) -> None:
158
161
  """Fuses, balance fuses, dependency graph and substrates."""
159
- chain_id = data.chain_id
160
162
  _print_fuse_section(
161
163
  "Fuses",
162
164
  data.fuses,
163
165
  data.fuse_markets,
164
166
  data.market_substrates,
165
- chain_id,
166
- api_key,
167
+ resolve_name,
167
168
  )
168
169
  click.echo()
169
170
 
@@ -172,18 +173,17 @@ def _print_markets(data: VaultData, api_key: str | None) -> None:
172
173
  data.instant_fuses,
173
174
  data.fuse_markets,
174
175
  data.market_substrates,
175
- chain_id,
176
- api_key,
176
+ resolve_name,
177
177
  )
178
178
  click.echo()
179
179
 
180
- _print_balance_fuses_table(data, api_key)
180
+ _print_balance_fuses_table(data, resolve_name)
181
181
  click.echo()
182
182
 
183
183
  _print_dependency_graph(data)
184
184
 
185
185
  click.echo("Substrates per Market:")
186
- _print_market_substrates(data, api_key)
186
+ _print_market_substrates(data, resolve_name)
187
187
  click.echo()
188
188
 
189
189
 
@@ -235,8 +235,7 @@ def _print_fuse_section(
235
235
  fuses: Sequence[FuseAddress],
236
236
  fuse_markets: dict[FuseAddress, MarketId] | None,
237
237
  market_substrates: dict[MarketId, list[bytes]] | None,
238
- chain_id: ChainId,
239
- api_key: str | None,
238
+ resolve_name: NameResolver,
240
239
  ) -> None:
241
240
  """Render a fuse section (regular or instant-withdrawal) with a unified
242
241
  layout.
@@ -262,10 +261,7 @@ def _print_fuse_section(
262
261
  return
263
262
 
264
263
  with ThreadPoolExecutor() as pool:
265
- name_futs = {
266
- addr: pool.submit(get_contract_name, chain_id, addr, api_key)
267
- for addr in counts
268
- }
264
+ name_futs = {addr: pool.submit(resolve_name, addr) for addr in counts}
269
265
  rows: list[tuple[str, ...]] = []
270
266
  for idx, addr in enumerate(counts, 1):
271
267
  market_label = "?"
@@ -285,7 +281,7 @@ def _print_fuse_section(
285
281
  _print_table(("#", "Address", "Contract", "Market", "Substrates"), rows)
286
282
 
287
283
 
288
- def _print_balance_fuses_table(data: VaultData, api_key: str | None) -> None:
284
+ def _print_balance_fuses_table(data: VaultData, resolve_name: NameResolver) -> None:
289
285
  balance_fuses = data.balance_fuses
290
286
  decimals = data.asset_decimals
291
287
  asset_symbol = data.asset_symbol
@@ -294,9 +290,7 @@ def _print_balance_fuses_table(data: VaultData, api_key: str | None) -> None:
294
290
  futures: list[tuple[int, MarketId, str, Future]] = []
295
291
  for idx, balance_fuse in enumerate(balance_fuses, 1):
296
292
  market_id_str = format_market_label(balance_fuse.market_id)
297
- f_contract = pool.submit(
298
- get_contract_name, data.chain_id, balance_fuse.fuse, api_key
299
- )
293
+ f_contract = pool.submit(resolve_name, balance_fuse.fuse)
300
294
  futures.append((idx, balance_fuse.market_id, market_id_str, f_contract))
301
295
 
302
296
  venue_rows: list[tuple[str, ...]] = []
@@ -328,18 +322,18 @@ def _print_balance_fuses_table(data: VaultData, api_key: str | None) -> None:
328
322
  _print_table(header, [(str(i), *row) for i, row in enumerate(zero_rows, 1)])
329
323
 
330
324
 
331
- def _print_market_substrates(data: VaultData, api_key: str | None) -> set[str]:
325
+ def _print_market_substrates(data: VaultData, resolve_name: NameResolver) -> set[str]:
332
326
  if GET_MARKET_SUBSTRATES in data.unimplemented_getters:
333
327
  click.secho(
334
328
  f" (unavailable: the vault predates {GET_MARKET_SUBSTRATES})",
335
329
  fg="yellow",
336
330
  )
337
331
  return set()
338
- return _print_substrates(data, api_key)
332
+ return _print_substrates(data, resolve_name)
339
333
 
340
334
 
341
335
  def _print_substrates( # noqa: C901
342
- data: VaultData, api_key: str | None
336
+ data: VaultData, resolve_name: NameResolver
343
337
  ) -> set[str]:
344
338
  substrates_by_market = data.market_substrates or {}
345
339
  balance_fuses = data.balance_fuses
@@ -364,8 +358,7 @@ def _print_substrates( # noqa: C901
364
358
  resolved_symbols = data.token_symbols
365
359
  with ThreadPoolExecutor() as pool:
366
360
  contract_futs = {
367
- addr: pool.submit(get_contract_name, data.chain_id, addr, api_key)
368
- for addr in all_addresses
361
+ addr: pool.submit(resolve_name, addr) for addr in all_addresses
369
362
  }
370
363
  resolved_contracts = {addr: fut.result() for addr, fut in contract_futs.items()}
371
364
 
@@ -191,7 +191,7 @@ class PlasmaVault(ContractWrapper):
191
191
  `addFuses` steps must be reverted before the vault is usable."""
192
192
  return self._write("removeFuses(address[])", fuses)
193
193
 
194
- def set_total_supply_cap(self, cap: Amount) -> Call[None]:
194
+ def set_total_supply_cap(self, cap: Shares) -> Call[None]:
195
195
  return self._write("setTotalSupplyCap(uint256)", cap)
196
196
 
197
197
  def convert_to_public_vault(self) -> Call[None]:
@@ -362,25 +362,26 @@ class PlasmaVault(ContractWrapper):
362
362
  "configureInstantWithdrawalFuses((address,bytes32[])[])", normalized
363
363
  )
364
364
 
365
- def transfer(self, to: ChecksumAddress, value: Amount) -> Call[None]:
365
+ def transfer(self, to: ChecksumAddress, value: Shares) -> Call[None]:
366
366
  return self._write("transfer(address,uint256)", to, value)
367
367
 
368
- def approve(self, account: ChecksumAddress, amount: Amount) -> Call[None]:
368
+ def approve(self, account: ChecksumAddress, amount: Shares) -> Call[None]:
369
369
  return self._write("approve(address,uint256)", account, amount)
370
370
 
371
371
  def transfer_from(
372
- self, _from: ChecksumAddress, to: ChecksumAddress, amount: Amount
372
+ self, _from: ChecksumAddress, to: ChecksumAddress, amount: Shares
373
373
  ) -> Call[None]:
374
374
  return self._write("transferFrom(address,address,uint256)", _from, to, amount)
375
375
 
376
- def balance_of(self, account: ChecksumAddress) -> Call[Amount]:
376
+ def balance_of(self, account: ChecksumAddress) -> Call[Shares]:
377
377
  return self._view(
378
- "balanceOf(address)", account, output_types=["uint256"], decoder=Amount
378
+ "balanceOf(address)", account, output_types=["uint256"], decoder=Shares
379
379
  )
380
380
 
381
- def get_total_supply_cap(self) -> Call[Amount]:
381
+ def get_total_supply_cap(self) -> Call[Shares]:
382
+ """The maximum total supply, in shares (``2**256 - 1``: uncapped)."""
382
383
  return self._view(
383
- "getTotalSupplyCap()", output_types=["uint256"], decoder=Amount
384
+ "getTotalSupplyCap()", output_types=["uint256"], decoder=Shares
384
385
  )
385
386
 
386
387
  def max_withdraw(self, account: ChecksumAddress) -> Call[Amount]:
@@ -418,8 +419,8 @@ class PlasmaVault(ContractWrapper):
418
419
  def total_assets(self) -> Call[Amount]:
419
420
  return self._view("totalAssets()", output_types=["uint256"], decoder=Amount)
420
421
 
421
- def total_supply(self) -> Call[Amount]:
422
- return self._view("totalSupply()", output_types=["uint256"], decoder=Amount)
422
+ def total_supply(self) -> Call[Shares]:
423
+ return self._view("totalSupply()", output_types=["uint256"], decoder=Shares)
423
424
 
424
425
  def name(self) -> Call[str]:
425
426
  return self._view("name()", output_types=["string"])
@@ -13,6 +13,7 @@ from dataclasses import dataclass, field
13
13
  from typing import Protocol, TypeVar
14
14
 
15
15
  from eth_typing import ChecksumAddress
16
+ from web3.types import Timestamp
16
17
 
17
18
  from ipor_fusion.core.context import Web3Context
18
19
  from ipor_fusion.core.plasma_vault import BalanceFuse
@@ -24,7 +25,15 @@ from ipor_fusion.dependency_graph import (
24
25
  from ipor_fusion.market_ids import IporFusionMarkets
25
26
  from ipor_fusion.readers.lending_health import VaultLendingHealth
26
27
  from ipor_fusion.substrates import decode_substrate, format_market_label
27
- from ipor_fusion.types import ChainId, FuseAddress, MarketId, PlasmaVaultAddress
28
+ from ipor_fusion.types import (
29
+ Amount,
30
+ ChainId,
31
+ Decimals,
32
+ FuseAddress,
33
+ MarketId,
34
+ PlasmaVaultAddress,
35
+ Shares,
36
+ )
28
37
  from ipor_fusion.types import Check as Check
29
38
  from ipor_fusion.types import Severity as Severity
30
39
  from ipor_fusion.types import Verdict as Verdict
@@ -57,9 +66,9 @@ class WithdrawQueue(Protocol):
57
66
  """The WithdrawManager state the reconciliation needs."""
58
67
 
59
68
  @property
60
- def shares_to_release(self) -> int: ...
69
+ def shares_to_release(self) -> Shares: ...
61
70
  @property
62
- def shares_to_release_assets(self) -> int | None: ...
71
+ def shares_to_release_assets(self) -> Amount | None: ...
63
72
 
64
73
 
65
74
  class UnpriceableToken(Protocol):
@@ -97,19 +106,19 @@ class VaultState(Protocol):
97
106
  @property
98
107
  def block_number(self) -> int: ...
99
108
  @property
100
- def block_timestamp(self) -> int: ...
109
+ def block_timestamp(self) -> Timestamp: ...
101
110
  @property
102
111
  def asset(self) -> ChecksumAddress: ...
103
112
  @property
104
113
  def asset_symbol(self) -> str: ...
105
114
  @property
106
- def asset_decimals(self) -> int: ...
115
+ def asset_decimals(self) -> Decimals: ...
107
116
  @property
108
117
  def asset_price_usd(self) -> float | None: ...
109
118
  @property
110
- def total_assets(self) -> int: ...
119
+ def total_assets(self) -> Amount: ...
111
120
  @property
112
- def underlying_balance_on_vault(self) -> int: ...
121
+ def underlying_balance_on_vault(self) -> Amount: ...
113
122
  @property
114
123
  def price_oracle_addr(self) -> ChecksumAddress: ...
115
124
  @property
@@ -129,7 +138,7 @@ class VaultState(Protocol):
129
138
  @property
130
139
  def unimplemented_getters(self) -> Sequence[str]: ...
131
140
  @property
132
- def market_balances(self) -> Mapping[MarketId, int]: ...
141
+ def market_balances(self) -> Mapping[MarketId, Amount]: ...
133
142
  @property
134
143
  def erc20(self) -> Erc20Holdings: ...
135
144
 
@@ -18,7 +18,7 @@ from typing import Any, TypeVar
18
18
  from eth_typing import HexAddress
19
19
  from eth_utils import function_signature_to_4byte_selector
20
20
  from web3 import Web3
21
- from web3.types import ChecksumAddress
21
+ from web3.types import ChecksumAddress, Timestamp
22
22
 
23
23
  from ipor_fusion.cache import CacheKey, cache_get, cache_key, cache_put
24
24
  from ipor_fusion.chains import ensure_supported_chain
@@ -57,10 +57,13 @@ from ipor_fusion.readers.unpriceable import (
57
57
  from ipor_fusion.substrates import decode_substrate
58
58
  from ipor_fusion.types import (
59
59
  AccessManagerAddress,
60
+ Amount,
60
61
  ChainId,
62
+ Decimals,
61
63
  FuseAddress,
62
64
  MarketId,
63
65
  PlasmaVaultAddress,
66
+ Shares,
64
67
  parse_hex_address,
65
68
  )
66
69
  from ipor_fusion.vault_erc20 import Erc20Holdings, _Asset, _read_erc20_holdings
@@ -115,12 +118,12 @@ class VaultData:
115
118
  chain_id: ChainId
116
119
  block_number: int
117
120
  is_latest: bool
118
- block_timestamp: int
119
- share_decimals: int
120
- asset_decimals: int
121
- total_assets: int
122
- total_supply: int
123
- supply_cap: int
121
+ block_timestamp: Timestamp
122
+ share_decimals: Decimals
123
+ asset_decimals: Decimals
124
+ total_assets: Amount
125
+ total_supply: Shares
126
+ supply_cap: Shares
124
127
  asset: ChecksumAddress
125
128
  asset_symbol: str
126
129
  access_manager: AccessManagerAddress
@@ -135,10 +138,10 @@ class VaultData:
135
138
  # totalAssets via ERC4626 base accounting; by design NOT tracked as an
136
139
  # ERC20_VAULT_BALANCE substrate, so it is read directly in
137
140
  # fetch_vault_data rather than derived from substrates.
138
- underlying_balance_on_vault: int = 0
141
+ underlying_balance_on_vault: Amount = Amount(0)
139
142
  vault_name: str = ""
140
143
  deployment_block: int | None = None
141
- deployment_timestamp: int | None = None
144
+ deployment_timestamp: Timestamp | None = None
142
145
  # Short error code from `fetch_deployment_info` when block/timestamp could
143
146
  # not be resolved. Surfaced in CLI output and the JSON `deployment` field
144
147
  # so users can distinguish "lookup not attempted/failed" from
@@ -186,7 +189,7 @@ class VaultData:
186
189
  unimplemented_getters: list[str] = field(default_factory=list)
187
190
  # totalAssetsInMarket of every balance-fuse market, once per market, in
188
191
  # balance-fuse order.
189
- market_balances: dict[MarketId, int] = field(default_factory=dict)
192
+ market_balances: dict[MarketId, Amount] = field(default_factory=dict)
190
193
  # The ERC20_VAULT_BALANCE tokens read directly (empty without that market).
191
194
  erc20: Erc20Holdings = field(default_factory=Erc20Holdings)
192
195
  # Symbols (lowercase address keys) of the substrate and breakdown tokens,
@@ -215,7 +218,7 @@ def _fuse_market_id_call(fuse: ChecksumAddress) -> Call[int]:
215
218
  )
216
219
 
217
220
 
218
- _UNCAPPED = 2**256 - 1
221
+ _UNCAPPED = Shares(2**256 - 1)
219
222
 
220
223
 
221
224
  def _missing_required_getter(
@@ -252,9 +255,16 @@ def resolve_token_symbol(ctx: Web3Context, address: HexAddress) -> str:
252
255
  return symbol
253
256
 
254
257
 
255
- def _cached_decimals(cached: dict[CacheKey, str], key: CacheKey) -> int | None:
256
- value = cached.get(key)
257
- return int(value) if value is not None and value.isdigit() else None
258
+ def _cached_int(cached: dict[CacheKey, str], key: CacheKey) -> int | None:
259
+ """A cached non-negative integer; anything else (a corrupt or foreign
260
+ entry) is a miss."""
261
+ value = cached.get(key, "")
262
+ if not (value.isascii() and value.isdigit()):
263
+ return None
264
+ try:
265
+ return int(value)
266
+ except ValueError: # beyond the int-string conversion limit
267
+ return None
258
268
 
259
269
 
260
270
  def resolve_token_decimals(ctx: Web3Context, address: HexAddress) -> int | None:
@@ -262,7 +272,7 @@ def resolve_token_decimals(ctx: Web3Context, address: HexAddress) -> int | None:
262
272
  (not cached) when ``address`` has no code at the context's block or does
263
273
  not answer."""
264
274
  key = cache_key(ctx.chain_id, address, "decimals")
265
- if (cached := _cached_decimals(cache_get(ctx.cache, [key]), key)) is not None:
275
+ if (cached := _cached_int(cache_get(ctx.cache, [key]), key)) is not None:
266
276
  return cached
267
277
 
268
278
  checksum = Web3.to_checksum_address(address)
@@ -278,7 +288,7 @@ def resolve_token_decimals(ctx: Web3Context, address: HexAddress) -> int | None:
278
288
  return decimals
279
289
 
280
290
 
281
- def _block_timestamp(ctx: Web3Context, block: int) -> int:
291
+ def _block_timestamp(ctx: Web3Context, block: int) -> Timestamp:
282
292
  return ctx.web3.eth.get_block(block)["timestamp"]
283
293
 
284
294
 
@@ -428,7 +438,7 @@ class _MarketReads:
428
438
  # Only markets with at least one substrate.
429
439
  market_substrates: dict[MarketId, list[bytes]]
430
440
  aave_pools: dict[MarketId, ChecksumAddress]
431
- market_balances: dict[MarketId, int]
441
+ market_balances: dict[MarketId, Amount]
432
442
  # False when the vault predates getMarketSubstrates (substrates unknown).
433
443
  substrates_available: bool = True
434
444
 
@@ -696,7 +706,7 @@ def _token_metadata(
696
706
  decimals: dict[HexAddress, int | None] = {
697
707
  a: value
698
708
  for a, k in decimals_keys.items()
699
- if (value := _cached_decimals(cached, k)) is not None
709
+ if (value := _cached_int(cached, k)) is not None
700
710
  }
701
711
  missing_symbols = sorted((breakdown | substrate_addresses) - symbols.keys())
702
712
  missing_decimals = sorted(breakdown - decimals.keys())
@@ -756,7 +766,7 @@ def fetch_deployment_info(
756
766
  vault_address: PlasmaVaultAddress,
757
767
  *,
758
768
  api_key: str | None = None,
759
- ) -> tuple[int | None, int | None, str | None]:
769
+ ) -> tuple[int | None, Timestamp | None, str | None]:
760
770
  """Return ``(block, timestamp, error)`` for the vault deployment, cached in
761
771
  ``ctx.cache``.
762
772
 
@@ -771,10 +781,10 @@ def fetch_deployment_info(
771
781
  block_key = cache_key(chain_id, vault_address, "deployment_block")
772
782
  time_key = cache_key(chain_id, vault_address, "deployment_timestamp")
773
783
  cached = cache_get(ctx.cache, [block_key, time_key])
774
- if (block := cached.get(block_key, "")).isdigit() and (
775
- stamp := cached.get(time_key, "")
776
- ).isdigit():
777
- return int(block), int(stamp), None
784
+ block = _cached_int(cached, block_key)
785
+ stamp = _cached_int(cached, time_key)
786
+ if block is not None and stamp is not None:
787
+ return block, Timestamp(stamp), None
778
788
 
779
789
  tx_hash, error = get_deployment_tx(chain_id, vault_address, api_key)
780
790
  if not tx_hash:
@@ -783,7 +793,7 @@ def fetch_deployment_info(
783
793
  try:
784
794
  tx = ctx.web3.eth.get_transaction(tx_hash)
785
795
  block_number: int = tx["blockNumber"]
786
- timestamp: int = ctx.web3.eth.get_block(block_number)["timestamp"]
796
+ timestamp: Timestamp = ctx.web3.eth.get_block(block_number)["timestamp"]
787
797
  except Exception:
788
798
  return None, None, "rpc-fetch-failed"
789
799
  cache_put(ctx.cache, {block_key: str(block_number), time_key: str(timestamp)})
@@ -6,7 +6,6 @@ from __future__ import annotations
6
6
  from collections.abc import Callable
7
7
  from concurrent.futures import Future, ThreadPoolExecutor
8
8
  from datetime import UTC, datetime
9
- from functools import partial
10
9
  from typing import Any
11
10
 
12
11
  from eth_typing import HexAddress
@@ -14,7 +13,6 @@ from eth_typing import HexAddress
14
13
  from ipor_fusion.chains import CHAIN_NAMES
15
14
  from ipor_fusion.core.fee_manager import HighWaterMarkPerformanceFee, RecipientFee
16
15
  from ipor_fusion.core.plasma_vault import BalanceFuse
17
- from ipor_fusion.explorer import get_contract_name
18
16
  from ipor_fusion.field_docs import DOCS
19
17
  from ipor_fusion.readers.aave_v3 import AaveV3PositionBreakdown
20
18
  from ipor_fusion.readers.hypercore import HyperCorePendingState, HyperCorePerpLeg
@@ -647,7 +645,7 @@ def _supply_cap_json(data: VaultData) -> dict[str, Any]:
647
645
  "formatted": (
648
646
  "unlimited"
649
647
  if data.supply_cap == UINT256_MAX
650
- else _format_amount(data.supply_cap, data.asset_decimals)
648
+ else _format_amount(data.supply_cap, data.share_decimals)
651
649
  ),
652
650
  }
653
651
 
@@ -705,6 +703,10 @@ def _markets_json(
705
703
  return markets
706
704
 
707
705
 
706
+ def _no_name(_address: HexAddress) -> str:
707
+ return ""
708
+
709
+
708
710
  def build_vault_info_json(
709
711
  data: VaultData,
710
712
  *,
@@ -716,14 +718,14 @@ def build_vault_info_json(
716
718
  ``data`` comes from `fetch_vault_data` (with ``metadata=True`` for token
717
719
  symbols); set its ``deployment_*`` fields first (`fetch_deployment_info`)
718
720
  for the ``deployment`` block. ``resolve_name`` names the fuses and
719
- substrate contracts (address to contract name, ``""`` when unknown); the
720
- default reads `ipor_fusion.explorer.get_contract_name` without an API key,
721
- so only names already in the on-disk cache.
721
+ substrate contracts (address to contract name, ``""`` when unknown), for
722
+ example `ipor_fusion.explorer.get_contract_name` bound to the chain, an
723
+ API key and ``ctx.cache``; without it no contract is named.
722
724
  """
723
725
  chain_id = data.chain_id
724
726
  chain_label = CHAIN_NAMES.get(chain_id, str(chain_id))
725
727
  if resolve_name is None:
726
- resolve_name = partial(get_contract_name, chain_id)
728
+ resolve_name = _no_name
727
729
 
728
730
  markets = _markets_json(data, resolve_name)
729
731
  validation = validate_vault_state(data)