ipor-fusion 4.0.0.dev151__tar.gz → 4.0.0.dev153__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.
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/AGENTS.md +21 -11
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/MIGRATION_4.md +43 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/pyproject.toml +3 -2
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/__init__.py +101 -1
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/vault_cmd.py +34 -3
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/vault_info_view.py +4 -3
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/vault_markets_view.py +7 -7
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/__init__.py +7 -1
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/access.py +12 -1
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/fusion_factory.py +34 -36
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/events.py +5 -2
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/indexer.py +22 -13
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/stargate/transport.py +20 -17
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/transport.py +2 -2
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/external_state_events.py +14 -9
- ipor_fusion-4.0.0.dev153/src/ipor_fusion/market_info.py +396 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/mcp/models.py +8 -6
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/morpho_api.py +192 -132
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/vault_info.py +500 -90
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_helpers.py +10 -4
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_market_morpho_blue.py +8 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_pending_requests_scan.py +3 -1
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_ccip_events.py +11 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_transport.py +15 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_external_state_events.py +9 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_mcp_models.py +218 -112
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_public_api.py +98 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_crosschain_hyperevm.py +19 -7
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/typed_client/consumer.py +40 -3
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/typed_client/rejected.py +13 -0
- ipor_fusion-4.0.0.dev151/src/ipor_fusion/market_info.py +0 -223
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/README.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/mcp/server.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/vault_data.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_vault_data_block.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/uv.lock +0 -0
|
@@ -186,7 +186,7 @@ the lifecycle matrix follows that.
|
|
|
186
186
|
| Python 3.12 runtime, 3.11 floor | `.python-version` + CI `python-version` default; `requires-python`, ruff `target-version`, pyright `pythonVersion` |
|
|
187
187
|
| `IporFusionMarkets`, `Roles` | `market_ids.py`, `config/roles.py` mirror `IporFusionMarkets.sol`, `Roles.sol` in `ipor-fusion/contracts/libraries/`; drift-gated by `tests/test_solidity_mirrors.py` — bump its pinned ref in the same change that syncs the mirrors An id sourced from a contracts feature branch ahead of the pinned ref goes in the test's `_AHEAD_OF_UPSTREAM` allowlist and is removed when the ref catches up |
|
|
188
188
|
| substrate decoders | `substrates.py` registry mirrors each market's `contracts/fuses/<protocol>/*SubstrateLib.sol` or `*FuseLib.sol` |
|
|
189
|
-
| `vault_info` JSON
|
|
189
|
+
| `vault_info` / `fusion market` JSON shapes | the builders and their TypedDicts (`VaultInfoJson`, `MorphoBlueMarketJson`, `MetaMorphoV1Json` / `MetaMorphoV2Json`) in `vault_info.py` / `market_info.py`, models in `mcp/models.py` (`extra="forbid"`, the published schema), the `VaultInfoJson`-typed `_full_vault_info_dict` fixture in `test_mcp_models.py` |
|
|
190
190
|
| CLI command set | every CLI command has a matching tool in `mcp/server.py` (`changelog` maps to `server_info`) |
|
|
191
191
|
|
|
192
192
|
## Layout (`src/ipor_fusion/`)
|
|
@@ -213,8 +213,8 @@ the lifecycle matrix follows that.
|
|
|
213
213
|
prices) and `vault_erc20.py` (the ERC20_VAULT_BALANCE holdings);
|
|
214
214
|
`vault_info.py` — `build_vault_info_json(data)`, the `fusion vault info --json`
|
|
215
215
|
document rendered from the snapshot alone (contract names via an injected
|
|
216
|
-
`resolve_name`)
|
|
217
|
-
and `health_check_lists`; `explorer.py` Etherscan V2 (single endpoint, needs API key);
|
|
216
|
+
`resolve_name`) and typed block by block (`VaultInfoJson` and its nested
|
|
217
|
+
TypedDicts), and `health_check_lists`; `explorer.py` Etherscan V2 (single endpoint, needs API key);
|
|
218
218
|
`cache.py` the `ContractCache` protocol (`get`/`put` of immutable facts keyed
|
|
219
219
|
`CacheKey(chain_id, address, field)`), `FileContractCache` (one JSON file, atomic
|
|
220
220
|
replace, corrupt/unwritable degrades to memory) and `NullCache`; every SDK use goes
|
|
@@ -223,8 +223,14 @@ the lifecycle matrix follows that.
|
|
|
223
223
|
`$XDG_CACHE_HOME/ipor-fusion/`) or `get_contract_name(cache=...)`. Never cache an
|
|
224
224
|
absence (no code, no answer): it can change at a later block.
|
|
225
225
|
`morpho_api.py` the Morpho public GraphQL API client (`fetch_market`, `fetch_vault`,
|
|
226
|
-
`PUBLIC_ALLOCATOR_ADDRESSES
|
|
227
|
-
`
|
|
226
|
+
`PUBLIC_ALLOCATOR_ADDRESSES`; it narrows the GraphQL body from `object`);
|
|
227
|
+
`market_info.py` — `build_morpho_blue_market_json`, `build_meta_morpho_json`, the
|
|
228
|
+
`fusion market` JSON documents (`MorphoBlueMarketJson`, `MetaMorphoV1Json` /
|
|
229
|
+
`MetaMorphoV2Json`). A JSON document is a TypedDict (`NotRequired` for a key only
|
|
230
|
+
some entries carry), never `dict[str, Any]`; JSON parsed from the network or a
|
|
231
|
+
caller enters as `object` / `Mapping[str, object]` and is narrowed with
|
|
232
|
+
`isinstance`. These two modules skip `from __future__ import annotations`, so a
|
|
233
|
+
TypedDict's `__optional_keys__` is right at run time.
|
|
228
234
|
None of them imports `cli/` (`tests/test_sdk_layering.py`)
|
|
229
235
|
- `config/roles.py` — `Roles` IntEnum
|
|
230
236
|
- `core/` — `context` (`Web3Context`), `contract` (`Call`, `ContractWrapper`),
|
|
@@ -431,12 +437,16 @@ value sets are `Literal` enums. The docstring keeps only what has no
|
|
|
431
437
|
structured home: a one-line summary, behavioral notes, cost warnings. Do not
|
|
432
438
|
repeat schema content as prose; it drifts.
|
|
433
439
|
|
|
434
|
-
`mcp/models.py` forbids extra keys
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
`
|
|
439
|
-
|
|
440
|
+
`mcp/models.py` forbids extra keys and stays the source of the published JSON
|
|
441
|
+
schema. Adding a field to `build_vault_info_json` (or a `fusion market` document)
|
|
442
|
+
means adding it to its TypedDict, to the matching model (with a default for
|
|
443
|
+
back-compat) and to the `_full_vault_info_dict` fixture;
|
|
444
|
+
`TestTypedDocumentsMirrorModels` in `test_mcp_models.py` holds every TypedDict to
|
|
445
|
+
its model block by block. The model keeps `dict[str, Any]` where the schema is
|
|
446
|
+
deliberately loose (`substrates`, `deployment`, `share_price`, `dependency_graph`,
|
|
447
|
+
`position_breakdown`): the SDK types those blocks, the schema does not validate
|
|
448
|
+
their inner keys. The substrate entries stay open-ended on both sides
|
|
449
|
+
(`SubstrateEntryJson`, `dict[str, str | bool]`): each decoder adds its own fields.
|
|
440
450
|
|
|
441
451
|
## Domain rules (verified against the contracts)
|
|
442
452
|
|
|
@@ -54,6 +54,10 @@ before it is fixed.
|
|
|
54
54
|
nominal types. Wrap literals and raw values, `ChainId(8453)`, `Period(0)`,
|
|
55
55
|
`Amount(n)`, `parse_fuse_address(...)`; values the SDK returns already carry
|
|
56
56
|
their type. See [Nominal types](#nominal-types).
|
|
57
|
+
9. **Typed JSON documents.** `build_vault_info_json` and the `fusion market`
|
|
58
|
+
builders return TypedDicts (`VaultInfoJson`, ...); code annotating them
|
|
59
|
+
`dict[str, Any]` switches to the TypedDict or `Mapping[str, object]`. See
|
|
60
|
+
[Typed JSON documents](#typed-json-documents).
|
|
57
61
|
|
|
58
62
|
Then read [Behavior changes](#behavior-changes): they apply to every caller,
|
|
59
63
|
type-checked or not.
|
|
@@ -721,6 +725,45 @@ string). Calling an MCP tool function
|
|
|
721
725
|
directly from Python takes `ChainId`. Their amount, decimals and time fields stay
|
|
722
726
|
`int`: they are JSON output models, and the SDK values above fit them unchanged.
|
|
723
727
|
|
|
728
|
+
## Typed JSON documents
|
|
729
|
+
|
|
730
|
+
The JSON document builders return `TypedDict`s instead of `dict[str, Any]`; the
|
|
731
|
+
documents themselves (keys, values, order, the MCP schemas) are unchanged, so
|
|
732
|
+
untyped code needs none of this section.
|
|
733
|
+
|
|
734
|
+
| Builder | Returns |
|
|
735
|
+
|---|---|
|
|
736
|
+
| `build_vault_info_json` | `VaultInfoJson` |
|
|
737
|
+
| `build_morpho_blue_market_json` | `MorphoBlueMarketJson` |
|
|
738
|
+
| `build_meta_morpho_json` | `MetaMorphoV1Json \| MetaMorphoV2Json`, told apart by `doc["version"]` |
|
|
739
|
+
| `RoleAccount.to_dict` | `RoleAccountJson` |
|
|
740
|
+
|
|
741
|
+
Every nested block has its own TypedDict (`FeesJson`, `WithdrawManagerJson`,
|
|
742
|
+
`BalanceFuseJson`, `ReconciliationJson`, `HyperCoreJson`, `MorphoSupplyingVaultJson`,
|
|
743
|
+
...), all importable from `ipor_fusion` and from `ipor_fusion.vault_info` /
|
|
744
|
+
`ipor_fusion.market_info` (`RoleAccountJson` from `ipor_fusion.core`). Values carry the
|
|
745
|
+
SDK's nominal types (`doc["vault"]` is a `PlasmaVaultAddress`, `doc["chain_id"]` a
|
|
746
|
+
`ChainId`). A block that can be `null` is `X | None`: check it before indexing
|
|
747
|
+
(`fees = doc["fees"]; if fees is not None: fees["management_fee_percent"]`). A key
|
|
748
|
+
that only some entries carry is `NotRequired` (a balance fuse's `pct_of_total` and
|
|
749
|
+
`position_breakdown`, the Morpho API keys of the market document): read it with
|
|
750
|
+
`.get`. A decoded substrate entry stays open-ended, `SubstrateEntryJson`
|
|
751
|
+
(`dict[str, str | bool]`), since each decoder adds its own fields.
|
|
752
|
+
|
|
753
|
+
- A variable or parameter annotated `dict[str, Any]` no longer accepts these
|
|
754
|
+
documents (a `TypedDict` is not a `dict[str, Any]`): annotate it with the TypedDict,
|
|
755
|
+
or `Mapping[str, object]` for code that only passes the document on (`json.dumps`
|
|
756
|
+
accepts either).
|
|
757
|
+
- Parsing entry points take `Mapping[str, object]` instead of `Mapping[str, Any]`:
|
|
758
|
+
`decode_external_state_event(log)` and `FusionInstance.from_dict(data)`.
|
|
759
|
+
`VerifierResult.message` is a `Mapping[str, object]`, and `OutboundMessage.raw` is
|
|
760
|
+
`object`: narrow it before use (`isinstance(message.raw, MessageV1)` for CCIP; a
|
|
761
|
+
Stargate `Packet`, or a `(Packet, TaxiMessage)` pair for a token transfer).
|
|
762
|
+
- The `vault info` document's `deployment` is `DeploymentJson` (block, timestamp,
|
|
763
|
+
age) or `DeploymentErrorJson` (`{"error": ...}`) or `None`; `share_price` is
|
|
764
|
+
`SharePriceJson` (`asset`, and `usd` when the asset is priced); `dependency_graph`
|
|
765
|
+
is `DependencyGraphJson` (`edges`, `update_reach`, `update_groups`).
|
|
766
|
+
|
|
724
767
|
## Behavior changes
|
|
725
768
|
|
|
726
769
|
These apply to every caller, type-checked or not. Changes described in full above
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ipor-fusion"
|
|
3
|
-
version = "4.0.0.
|
|
3
|
+
version = "4.0.0.dev153"
|
|
4
4
|
description = "The IPOR Fusion SDK for Python"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
|
|
@@ -111,7 +111,8 @@ executionEnvironments = [
|
|
|
111
111
|
{ root = "examples", reportArgumentType = "error" },
|
|
112
112
|
# A negative case is a line that must fail to type-check, marked with
|
|
113
113
|
# `# pyright: ignore[rule]`; an ignore that suppresses nothing is an error.
|
|
114
|
-
|
|
114
|
+
# A client reads the SDK's NotRequired document keys with .get().
|
|
115
|
+
{ root = "tests/typed_client", reportArgumentType = "error", reportUnnecessaryTypeIgnoreComment = "error", reportTypedDictNotRequiredAccess = "error" },
|
|
115
116
|
]
|
|
116
117
|
|
|
117
118
|
[tool.coverage.run]
|
|
@@ -27,6 +27,7 @@ from ipor_fusion.config.roles import Roles
|
|
|
27
27
|
from ipor_fusion.core.access import (
|
|
28
28
|
AccessManager,
|
|
29
29
|
RoleAccount,
|
|
30
|
+
RoleAccountJson,
|
|
30
31
|
RoleStatus,
|
|
31
32
|
resolve_access_manager,
|
|
32
33
|
role_account_sort_key,
|
|
@@ -318,6 +319,21 @@ from ipor_fusion.fuses.external_state_events import (
|
|
|
318
319
|
)
|
|
319
320
|
from ipor_fusion.market_ids import IporFusionMarkets
|
|
320
321
|
from ipor_fusion.market_info import (
|
|
322
|
+
MetaMorphoAdapterJson,
|
|
323
|
+
MetaMorphoAllocationJson,
|
|
324
|
+
MetaMorphoCapJson,
|
|
325
|
+
MetaMorphoFlowCapJson,
|
|
326
|
+
MetaMorphoPublicAllocatorJson,
|
|
327
|
+
MetaMorphoV1Json,
|
|
328
|
+
MetaMorphoV2Json,
|
|
329
|
+
MorphoAssetJson,
|
|
330
|
+
MorphoBlueMarketJson,
|
|
331
|
+
MorphoFlowCapConfigJson,
|
|
332
|
+
MorphoMarketParamsJson,
|
|
333
|
+
MorphoMarketRatesJson,
|
|
334
|
+
MorphoMarketStateJson,
|
|
335
|
+
MorphoSupplyingVaultJson,
|
|
336
|
+
MorphoVaultAssetJson,
|
|
321
337
|
build_meta_morpho_json,
|
|
322
338
|
build_morpho_blue_market_json,
|
|
323
339
|
)
|
|
@@ -480,7 +496,42 @@ from ipor_fusion.vault_data import (
|
|
|
480
496
|
resolve_token_decimals,
|
|
481
497
|
resolve_token_symbol,
|
|
482
498
|
)
|
|
483
|
-
from ipor_fusion.vault_info import
|
|
499
|
+
from ipor_fusion.vault_info import (
|
|
500
|
+
AaveBreakdownJson,
|
|
501
|
+
AmountJson,
|
|
502
|
+
BalanceFuseJson,
|
|
503
|
+
BreakdownAmountJson,
|
|
504
|
+
DeltaJson,
|
|
505
|
+
DependencyGraphJson,
|
|
506
|
+
DeploymentErrorJson,
|
|
507
|
+
DeploymentJson,
|
|
508
|
+
Erc20BalanceJson,
|
|
509
|
+
FeesJson,
|
|
510
|
+
FuseJson,
|
|
511
|
+
HealthCheckJson,
|
|
512
|
+
HighWaterMarkJson,
|
|
513
|
+
HyperCoreJson,
|
|
514
|
+
HyperCorePendingJson,
|
|
515
|
+
HyperCorePerpLegJson,
|
|
516
|
+
HyperCorePerpMarketJson,
|
|
517
|
+
HyperCoreSpotLegJson,
|
|
518
|
+
LendingHealthJson,
|
|
519
|
+
LendingMarketJson,
|
|
520
|
+
ManagersJson,
|
|
521
|
+
MorphoBreakdownJson,
|
|
522
|
+
PendingRequestJson,
|
|
523
|
+
PricedAmountJson,
|
|
524
|
+
RecipientFeeJson,
|
|
525
|
+
ReconciliationJson,
|
|
526
|
+
SharePriceJson,
|
|
527
|
+
SubstrateEntryJson,
|
|
528
|
+
UsdAmountJson,
|
|
529
|
+
VaultAssetJson,
|
|
530
|
+
VaultInfoJson,
|
|
531
|
+
VaultLinksJson,
|
|
532
|
+
WithdrawManagerJson,
|
|
533
|
+
build_vault_info_json,
|
|
534
|
+
)
|
|
484
535
|
|
|
485
536
|
__version__ = package_version()
|
|
486
537
|
|
|
@@ -526,6 +577,7 @@ __all__ = [
|
|
|
526
577
|
"PlasmaVault",
|
|
527
578
|
"AccessManager",
|
|
528
579
|
"RoleAccount",
|
|
580
|
+
"RoleAccountJson",
|
|
529
581
|
"RoleStatus",
|
|
530
582
|
"resolve_access_manager",
|
|
531
583
|
"role_account_sort_key",
|
|
@@ -919,6 +971,39 @@ __all__ = [
|
|
|
919
971
|
"resolve_token_decimals",
|
|
920
972
|
"resolve_token_symbol",
|
|
921
973
|
"build_vault_info_json",
|
|
974
|
+
"AaveBreakdownJson",
|
|
975
|
+
"AmountJson",
|
|
976
|
+
"BalanceFuseJson",
|
|
977
|
+
"BreakdownAmountJson",
|
|
978
|
+
"DeltaJson",
|
|
979
|
+
"DependencyGraphJson",
|
|
980
|
+
"DeploymentErrorJson",
|
|
981
|
+
"DeploymentJson",
|
|
982
|
+
"Erc20BalanceJson",
|
|
983
|
+
"FeesJson",
|
|
984
|
+
"FuseJson",
|
|
985
|
+
"HealthCheckJson",
|
|
986
|
+
"HighWaterMarkJson",
|
|
987
|
+
"HyperCoreJson",
|
|
988
|
+
"HyperCorePendingJson",
|
|
989
|
+
"HyperCorePerpLegJson",
|
|
990
|
+
"HyperCorePerpMarketJson",
|
|
991
|
+
"HyperCoreSpotLegJson",
|
|
992
|
+
"LendingHealthJson",
|
|
993
|
+
"LendingMarketJson",
|
|
994
|
+
"ManagersJson",
|
|
995
|
+
"MorphoBreakdownJson",
|
|
996
|
+
"PendingRequestJson",
|
|
997
|
+
"PricedAmountJson",
|
|
998
|
+
"RecipientFeeJson",
|
|
999
|
+
"ReconciliationJson",
|
|
1000
|
+
"SharePriceJson",
|
|
1001
|
+
"SubstrateEntryJson",
|
|
1002
|
+
"UsdAmountJson",
|
|
1003
|
+
"VaultAssetJson",
|
|
1004
|
+
"VaultInfoJson",
|
|
1005
|
+
"VaultLinksJson",
|
|
1006
|
+
"WithdrawManagerJson",
|
|
922
1007
|
"MorphoApiError",
|
|
923
1008
|
"MorphoApiMarket",
|
|
924
1009
|
"PUBLIC_ALLOCATOR_ADDRESSES",
|
|
@@ -933,4 +1018,19 @@ __all__ = [
|
|
|
933
1018
|
"fetch_vault",
|
|
934
1019
|
"build_meta_morpho_json",
|
|
935
1020
|
"build_morpho_blue_market_json",
|
|
1021
|
+
"MetaMorphoAdapterJson",
|
|
1022
|
+
"MetaMorphoAllocationJson",
|
|
1023
|
+
"MetaMorphoCapJson",
|
|
1024
|
+
"MetaMorphoFlowCapJson",
|
|
1025
|
+
"MetaMorphoPublicAllocatorJson",
|
|
1026
|
+
"MetaMorphoV1Json",
|
|
1027
|
+
"MetaMorphoV2Json",
|
|
1028
|
+
"MorphoAssetJson",
|
|
1029
|
+
"MorphoBlueMarketJson",
|
|
1030
|
+
"MorphoFlowCapConfigJson",
|
|
1031
|
+
"MorphoMarketParamsJson",
|
|
1032
|
+
"MorphoMarketRatesJson",
|
|
1033
|
+
"MorphoMarketStateJson",
|
|
1034
|
+
"MorphoSupplyingVaultJson",
|
|
1035
|
+
"MorphoVaultAssetJson",
|
|
936
1036
|
]
|
|
@@ -2,10 +2,11 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import sys
|
|
5
|
-
from typing import
|
|
5
|
+
from typing import TypedDict
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
from web3 import Web3
|
|
9
|
+
from web3.types import Timestamp
|
|
9
10
|
|
|
10
11
|
from ipor_fusion.chains import CHAIN_NAMES
|
|
11
12
|
from ipor_fusion.cli.config_store import (
|
|
@@ -41,7 +42,7 @@ from ipor_fusion.errors import (
|
|
|
41
42
|
from ipor_fusion.readers.oracle_mapping import (
|
|
42
43
|
build_oracle_mapping,
|
|
43
44
|
)
|
|
44
|
-
from ipor_fusion.types import ChainId, PlasmaVaultAddress
|
|
45
|
+
from ipor_fusion.types import ChainId, Check, PlasmaVaultAddress, Severity, Verdict
|
|
45
46
|
from ipor_fusion.validation import (
|
|
46
47
|
VaultValidation,
|
|
47
48
|
validate_vault,
|
|
@@ -51,6 +52,10 @@ from ipor_fusion.vault_data import (
|
|
|
51
52
|
fetch_vault_data,
|
|
52
53
|
)
|
|
53
54
|
from ipor_fusion.vault_info import (
|
|
55
|
+
Erc20BalanceJson,
|
|
56
|
+
LendingHealthJson,
|
|
57
|
+
ReconciliationJson,
|
|
58
|
+
VaultAssetJson,
|
|
54
59
|
_erc20_balances_json,
|
|
55
60
|
_lending_health_json,
|
|
56
61
|
_reconciliation_json,
|
|
@@ -58,6 +63,32 @@ from ipor_fusion.vault_info import (
|
|
|
58
63
|
)
|
|
59
64
|
|
|
60
65
|
|
|
66
|
+
class _FindingJson(TypedDict):
|
|
67
|
+
check: Check
|
|
68
|
+
severity: Severity
|
|
69
|
+
message: str
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class _ValidationJson(TypedDict):
|
|
73
|
+
"""The ``fusion vault validate --json`` document."""
|
|
74
|
+
|
|
75
|
+
vault: PlasmaVaultAddress
|
|
76
|
+
chain: str
|
|
77
|
+
chain_id: ChainId
|
|
78
|
+
block: int
|
|
79
|
+
block_timestamp: Timestamp
|
|
80
|
+
block_timestamp_utc: str
|
|
81
|
+
asset: VaultAssetJson
|
|
82
|
+
verdict: Verdict
|
|
83
|
+
criticals: list[str]
|
|
84
|
+
warnings: list[str]
|
|
85
|
+
ok: list[str]
|
|
86
|
+
findings: list[_FindingJson]
|
|
87
|
+
reconciliation: ReconciliationJson
|
|
88
|
+
erc20_balances: list[Erc20BalanceJson]
|
|
89
|
+
lending_health: LendingHealthJson | None
|
|
90
|
+
|
|
91
|
+
|
|
61
92
|
def _auto_save_vault(
|
|
62
93
|
cfg: FusionConfig,
|
|
63
94
|
vault_address: PlasmaVaultAddress,
|
|
@@ -276,7 +307,7 @@ def validate(
|
|
|
276
307
|
sys.exit(1)
|
|
277
308
|
|
|
278
309
|
|
|
279
|
-
def _validation_json(validation: VaultValidation, chain_label: str) ->
|
|
310
|
+
def _validation_json(validation: VaultValidation, chain_label: str) -> _ValidationJson:
|
|
280
311
|
return {
|
|
281
312
|
"vault": validation.vault,
|
|
282
313
|
"chain": chain_label,
|
{ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/vault_info_view.py
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
+
from collections.abc import Sequence
|
|
4
5
|
from functools import partial
|
|
5
|
-
from typing import Any
|
|
6
6
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
@@ -23,6 +23,7 @@ from ipor_fusion.cli.vault_rendering import (
|
|
|
23
23
|
_format_usd,
|
|
24
24
|
_print_table,
|
|
25
25
|
)
|
|
26
|
+
from ipor_fusion.core.access import RoleAccountJson
|
|
26
27
|
from ipor_fusion.core.context import Web3Context
|
|
27
28
|
from ipor_fusion.core.fee_manager import RecipientFee
|
|
28
29
|
from ipor_fusion.explorer import get_contract_name
|
|
@@ -48,7 +49,7 @@ from ipor_fusion.vault_info import (
|
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
|
|
51
|
-
def _print_role_accounts_table(role_accounts:
|
|
52
|
+
def _print_role_accounts_table(role_accounts: Sequence[RoleAccountJson]) -> None:
|
|
52
53
|
_print_table(
|
|
53
54
|
("Account", "Role", "Role ID", "Delay (s)"),
|
|
54
55
|
[
|
|
@@ -63,7 +64,7 @@ def _print_role_accounts_table(role_accounts: list[dict[str, Any]]) -> None:
|
|
|
63
64
|
)
|
|
64
65
|
|
|
65
66
|
|
|
66
|
-
def _print_role_accounts(role_accounts:
|
|
67
|
+
def _print_role_accounts(role_accounts: Sequence[RoleAccountJson] | None) -> None:
|
|
67
68
|
click.echo("Role Accounts:")
|
|
68
69
|
if role_accounts is None:
|
|
69
70
|
click.echo(" (unavailable — the RoleGranted log scan did not complete)")
|
{ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/cli/vault_markets_view.py
RENAMED
|
@@ -2,7 +2,6 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable, Sequence
|
|
4
4
|
from concurrent.futures import Future, ThreadPoolExecutor
|
|
5
|
-
from typing import Any
|
|
6
5
|
|
|
7
6
|
import click
|
|
8
7
|
from eth_typing import HexAddress
|
|
@@ -13,6 +12,7 @@ from ipor_fusion.cli.vault_rendering import (
|
|
|
13
12
|
_print_table,
|
|
14
13
|
_substrate_details,
|
|
15
14
|
)
|
|
15
|
+
from ipor_fusion.readers.lending_health import LendingMarketHealth, VaultLendingHealth
|
|
16
16
|
from ipor_fusion.substrates import (
|
|
17
17
|
decode_substrate,
|
|
18
18
|
format_market_label,
|
|
@@ -42,7 +42,7 @@ def _print_lending_health(data: VaultData) -> None: # noqa: C901
|
|
|
42
42
|
click.echo("Position Breakdown:")
|
|
43
43
|
morpho_health, aave_health = _index_lending_health(lh)
|
|
44
44
|
consumed_morpho_subs: set[str] = set()
|
|
45
|
-
consumed_aave_mids: set[
|
|
45
|
+
consumed_aave_mids: set[MarketId | str] = set()
|
|
46
46
|
|
|
47
47
|
for ipor_mid, positions in (data.morpho_positions or {}).items():
|
|
48
48
|
click.echo(f" {format_market_label(ipor_mid)}:")
|
|
@@ -98,16 +98,16 @@ def _print_lending_health(data: VaultData) -> None: # noqa: C901
|
|
|
98
98
|
|
|
99
99
|
|
|
100
100
|
def _index_lending_health(
|
|
101
|
-
lh:
|
|
102
|
-
) -> tuple[dict[str,
|
|
101
|
+
lh: VaultLendingHealth | None,
|
|
102
|
+
) -> tuple[dict[str, LendingMarketHealth], dict[MarketId | str, LendingMarketHealth]]:
|
|
103
103
|
"""Split lending health rows by protocol for fast lookup during rendering.
|
|
104
104
|
|
|
105
105
|
Morpho rows are keyed by morpho substrate id (one row per substrate).
|
|
106
106
|
Aave V3 rows are keyed by IPOR market id (account-aggregated, one row per
|
|
107
107
|
market); Aave V4 rows by Spoke address (account-aggregated per Spoke).
|
|
108
108
|
"""
|
|
109
|
-
morpho: dict[str,
|
|
110
|
-
aave: dict[
|
|
109
|
+
morpho: dict[str, LendingMarketHealth] = {}
|
|
110
|
+
aave: dict[MarketId | str, LendingMarketHealth] = {}
|
|
111
111
|
if lh is None:
|
|
112
112
|
return morpho, aave
|
|
113
113
|
for m in lh.markets:
|
|
@@ -120,7 +120,7 @@ def _index_lending_health(
|
|
|
120
120
|
return morpho, aave
|
|
121
121
|
|
|
122
122
|
|
|
123
|
-
def _print_health_lines(market:
|
|
123
|
+
def _print_health_lines(market: LendingMarketHealth, indent: str) -> None:
|
|
124
124
|
"""Render LTV / Health Factor / Status lines for a lending market.
|
|
125
125
|
|
|
126
126
|
Status colors: green when safe, yellow at warning (HF < 1.10), red+bold
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
from ipor_fusion.core.access import
|
|
1
|
+
from ipor_fusion.core.access import (
|
|
2
|
+
AccessManager,
|
|
3
|
+
RoleAccount,
|
|
4
|
+
RoleAccountJson,
|
|
5
|
+
RoleStatus,
|
|
6
|
+
)
|
|
2
7
|
from ipor_fusion.core.context import InFlightLimit, Web3Context
|
|
3
8
|
from ipor_fusion.core.erc20 import ERC20
|
|
4
9
|
from ipor_fusion.core.fee_manager import (
|
|
@@ -37,6 +42,7 @@ __all__ = [
|
|
|
37
42
|
"PlasmaVault",
|
|
38
43
|
"AccessManager",
|
|
39
44
|
"RoleAccount",
|
|
45
|
+
"RoleAccountJson",
|
|
40
46
|
"RoleStatus",
|
|
41
47
|
"RewardsManager",
|
|
42
48
|
"VestingData",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from collections.abc import Callable
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
+
from typing import TypedDict
|
|
3
4
|
|
|
4
5
|
from eth_abi import decode
|
|
5
6
|
from eth_abi.exceptions import InsufficientDataBytes
|
|
@@ -23,6 +24,16 @@ from ipor_fusion.errors import (
|
|
|
23
24
|
from ipor_fusion.types import AccessManagerAddress, Period, PlasmaVaultAddress, RoleId
|
|
24
25
|
|
|
25
26
|
|
|
27
|
+
class RoleAccountJson(TypedDict):
|
|
28
|
+
"""`RoleAccount.to_dict`: one role membership as JSON."""
|
|
29
|
+
|
|
30
|
+
account: ChecksumAddress
|
|
31
|
+
role_id: RoleId
|
|
32
|
+
role_name: str
|
|
33
|
+
is_member: bool
|
|
34
|
+
execution_delay: Period
|
|
35
|
+
|
|
36
|
+
|
|
26
37
|
@dataclass(slots=True)
|
|
27
38
|
class RoleStatus:
|
|
28
39
|
"""Result of a role membership check for an account."""
|
|
@@ -44,7 +55,7 @@ class RoleAccount:
|
|
|
44
55
|
def role_name(self) -> str:
|
|
45
56
|
return Roles.get_name(self.role_id)
|
|
46
57
|
|
|
47
|
-
def to_dict(self) ->
|
|
58
|
+
def to_dict(self) -> RoleAccountJson:
|
|
48
59
|
"""Canonical JSON-ready row shape, shared by the CLI surfaces."""
|
|
49
60
|
return {
|
|
50
61
|
"account": self.account,
|
{ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/core/fusion_factory.py
RENAMED
|
@@ -22,9 +22,8 @@ For external-signer flows, grab the bytes directly:
|
|
|
22
22
|
|
|
23
23
|
from __future__ import annotations
|
|
24
24
|
|
|
25
|
-
from collections.abc import
|
|
26
|
-
from dataclasses import dataclass
|
|
27
|
-
from typing import Any
|
|
25
|
+
from collections.abc import Mapping
|
|
26
|
+
from dataclasses import dataclass, fields
|
|
28
27
|
|
|
29
28
|
from eth_abi import decode as abi_decode
|
|
30
29
|
from eth_typing import ChecksumAddress
|
|
@@ -80,61 +79,60 @@ class FusionInstance:
|
|
|
80
79
|
price_manager: ChecksumAddress
|
|
81
80
|
|
|
82
81
|
@classmethod
|
|
83
|
-
def from_dict(
|
|
84
|
-
cls, data: Mapping[str,
|
|
85
|
-
) -> FusionInstance:
|
|
82
|
+
def from_dict( # proctor: ignore[primitives-untyped-dict]
|
|
83
|
+
cls, data: Mapping[str, object]
|
|
84
|
+
) -> FusionInstance:
|
|
86
85
|
"""Rebuild an instance from its JSON form (``dataclasses.asdict``),
|
|
87
86
|
parsing every field: role addresses through their parsers, the rest
|
|
88
87
|
checksummed, integers and strings type-checked. Raises ``ValueError``
|
|
89
88
|
on a missing, extra or malformed field."""
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
names = {f.name for f in fields(cls)}
|
|
90
|
+
missing = names - data.keys()
|
|
91
|
+
extra = data.keys() - names
|
|
92
92
|
if missing or extra:
|
|
93
93
|
raise ValueError(
|
|
94
94
|
f"FusionInstance fields: missing {sorted(missing)}, extra {sorted(extra)}"
|
|
95
95
|
)
|
|
96
96
|
return cls(
|
|
97
|
-
|
|
97
|
+
index=_integer(data["index"]),
|
|
98
|
+
version=_integer(data["version"]),
|
|
99
|
+
asset_name=_text(data["asset_name"]),
|
|
100
|
+
asset_symbol=_text(data["asset_symbol"]),
|
|
101
|
+
asset_decimals=Decimals(_integer(data["asset_decimals"])),
|
|
102
|
+
underlying_token=_address(data["underlying_token"]),
|
|
103
|
+
underlying_token_symbol=_text(data["underlying_token_symbol"]),
|
|
104
|
+
underlying_token_decimals=Decimals(
|
|
105
|
+
_integer(data["underlying_token_decimals"])
|
|
106
|
+
),
|
|
107
|
+
initial_owner=_address(data["initial_owner"]),
|
|
108
|
+
plasma_vault=parse_plasma_vault_address(_text(data["plasma_vault"])),
|
|
109
|
+
plasma_vault_base=_address(data["plasma_vault_base"]),
|
|
110
|
+
access_manager=parse_access_manager_address(_text(data["access_manager"])),
|
|
111
|
+
fee_manager=_address(data["fee_manager"]),
|
|
112
|
+
rewards_manager=_address(data["rewards_manager"]),
|
|
113
|
+
withdraw_manager=_address(data["withdraw_manager"]),
|
|
114
|
+
context_manager=_address(data["context_manager"]),
|
|
115
|
+
price_manager=_address(data["price_manager"]),
|
|
98
116
|
)
|
|
99
117
|
|
|
100
118
|
|
|
101
|
-
def _integer(value:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
119
|
+
def _integer(value: object) -> int:
|
|
120
|
+
# Exactly int: a bool or an IntEnum is not a JSON integer field.
|
|
121
|
+
if type(value) is int:
|
|
122
|
+
return value
|
|
123
|
+
raise ValueError(f"expected an integer: {value!r}")
|
|
105
124
|
|
|
106
125
|
|
|
107
|
-
def _text(value:
|
|
126
|
+
def _text(value: object) -> str:
|
|
108
127
|
if not isinstance(value, str):
|
|
109
128
|
raise ValueError(f"expected a string: {value!r}")
|
|
110
129
|
return value
|
|
111
130
|
|
|
112
131
|
|
|
113
|
-
def _address(value:
|
|
132
|
+
def _address(value: object) -> ChecksumAddress:
|
|
114
133
|
return Web3.to_checksum_address(_text(value))
|
|
115
134
|
|
|
116
135
|
|
|
117
|
-
_INSTANCE_FIELDS: dict[str, Callable[[Any], Any]] = {
|
|
118
|
-
"index": _integer,
|
|
119
|
-
"version": _integer,
|
|
120
|
-
"asset_name": _text,
|
|
121
|
-
"asset_symbol": _text,
|
|
122
|
-
"asset_decimals": lambda value: Decimals(_integer(value)),
|
|
123
|
-
"underlying_token": _address,
|
|
124
|
-
"underlying_token_symbol": _text,
|
|
125
|
-
"underlying_token_decimals": lambda value: Decimals(_integer(value)),
|
|
126
|
-
"initial_owner": _address,
|
|
127
|
-
"plasma_vault": lambda value: parse_plasma_vault_address(_text(value)),
|
|
128
|
-
"plasma_vault_base": _address,
|
|
129
|
-
"access_manager": lambda value: parse_access_manager_address(_text(value)),
|
|
130
|
-
"fee_manager": _address,
|
|
131
|
-
"rewards_manager": _address,
|
|
132
|
-
"withdraw_manager": _address,
|
|
133
|
-
"context_manager": _address,
|
|
134
|
-
"price_manager": _address,
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
|
|
138
136
|
_FUSION_INSTANCE_OUTPUT_TYPES: list[str] = [
|
|
139
137
|
"uint256", # index
|
|
140
138
|
"uint256", # version
|
{ipor_fusion-4.0.0.dev151 → ipor_fusion-4.0.0.dev153}/src/ipor_fusion/crosschain/ccip/events.py
RENAMED
|
@@ -19,7 +19,6 @@ from __future__ import annotations
|
|
|
19
19
|
from collections.abc import Iterable, Mapping
|
|
20
20
|
from dataclasses import dataclass
|
|
21
21
|
from types import MappingProxyType
|
|
22
|
-
from typing import Any
|
|
23
22
|
|
|
24
23
|
from eth_abi import decode
|
|
25
24
|
from eth_typing import ChecksumAddress
|
|
@@ -401,12 +400,16 @@ CCIP_EVENT_TOPICS: dict[bytes, CcipEventSpec] = {
|
|
|
401
400
|
}
|
|
402
401
|
|
|
403
402
|
|
|
404
|
-
def _python_value(abi_type: str, value:
|
|
403
|
+
def _python_value(abi_type: str, value: object) -> object:
|
|
405
404
|
"""Checksum an address, also inside a struct; ``int``, ``bool`` and
|
|
406
405
|
``bytes32`` values already decode to the Python type."""
|
|
407
406
|
if abi_type == "address":
|
|
407
|
+
if not isinstance(value, str):
|
|
408
|
+
raise TypeError(f"address decoded as {type(value).__name__}")
|
|
408
409
|
return Web3.to_checksum_address(value)
|
|
409
410
|
if abi_type.startswith("("):
|
|
411
|
+
if not isinstance(value, tuple):
|
|
412
|
+
raise TypeError(f"struct decoded as {type(value).__name__}")
|
|
410
413
|
# Flat split: no CCIP event nests a struct inside a struct.
|
|
411
414
|
return tuple(map(_python_value, abi_type[1:-1].split(","), value))
|
|
412
415
|
return value
|