ipor-fusion 4.0.0.dev222__tar.gz → 4.0.0.dev234__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.dev222 → ipor_fusion-4.0.0.dev234}/AGENTS.md +12 -3
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/MIGRATION_4.md +48 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/__init__.py +14 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/vault_cmd.py +5 -68
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/vault_markets_view.py +11 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/mcp/models.py +30 -223
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/mcp/server.py +5 -3
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/__init__.py +4 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/lending_health.py +104 -24
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/unpriceable.py +33 -7
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/types.py +1 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/validation.py +41 -2
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/vault_data.py +27 -3
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/vault_info.py +130 -22
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/vault_positions.py +10 -2
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/clean.json +1 -1
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/clean.mcp.json +4 -8
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/deployment_error.json +1 -1
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +4 -8
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/fetched.mcp.json +6 -12
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/full.json +1 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/full.mcp.json +16 -34
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/rich.json +1 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/rich.mcp.json +14 -30
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_helpers.py +27 -3
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_lending_health.py +49 -26
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_vault_validate.py +8 -3
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_mcp_models.py +14 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_mcp_vault_validate.py +66 -30
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_public_api.py +14 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_unpriceable_tokens.py +11 -2
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_validation.py +145 -2
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_vault_info_fetched_golden.py +1 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/README.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/simulation_result.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/hypercore/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_event_args.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_fake_rpc.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_golden.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_live.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_oracle_mapping_fake.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_blue.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/simulate_v1_request.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/fetched.json +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/full.txt +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_market_golden.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_oracle_mapping_golden.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulation_errors.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_simulation_observation.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_vault_data_block.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_vault_reconciliation_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/tests/typed_client/rejected.py +0 -0
- {ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/uv.lock +0 -0
|
@@ -487,9 +487,13 @@ structured home: a one-line summary, behavioral notes, cost warnings. Do not
|
|
|
487
487
|
repeat schema content as prose; it drifts.
|
|
488
488
|
|
|
489
489
|
`mcp/models.py` forbids extra keys and stays the source of the published JSON
|
|
490
|
-
schema.
|
|
491
|
-
|
|
492
|
-
|
|
490
|
+
schema. A command whose CLI `--json` and MCP tool return the same data publish one
|
|
491
|
+
document: an SDK builder returns its TypedDict (`build_vault_info_json`,
|
|
492
|
+
`build_vault_validation_json`, the `fusion market` builders) and the tool
|
|
493
|
+
validates it into the mirroring model, never a second hand-built shape. Adding a
|
|
494
|
+
field to a document means adding it to its TypedDict, to the matching model (with
|
|
495
|
+
a default for back-compat) and to the `_full_vault_info_dict` fixture for vault
|
|
496
|
+
info;
|
|
493
497
|
`TestTypedDocumentsMirrorModels` in `test_mcp_models.py` holds every TypedDict to
|
|
494
498
|
its model block by block, a union block (`deployment`, `position_breakdown`,
|
|
495
499
|
`source_detail`) shape by shape. Every block is a model; a block whose optional keys
|
|
@@ -533,6 +537,11 @@ decoder adds its own fields.
|
|
|
533
537
|
- `ZeroBalanceFuse` markets are capabilities (swap, flash-loan,
|
|
534
538
|
instant-withdrawal, admin) with structurally zero balance, not venues. They
|
|
535
539
|
go in `zero_balance_fuses` and are not counted as liquidity markets.
|
|
540
|
+
- A validation input that cannot be read is never a silent `ok`: a lending
|
|
541
|
+
position whose reads fail is an `UnreadableLendingMarket` (a `lending_health`
|
|
542
|
+
warning), a failed lending-health or unpriceable-token read is named in
|
|
543
|
+
`VaultData.failed_reads` (an `incomplete_read` warning). Catch the chain and
|
|
544
|
+
transport errors only; degrade-to-`None` is for display-only data.
|
|
536
545
|
- Reconciliation: `totalAssets = balance_fuses_sum + underlying_on_vault +
|
|
537
546
|
rewards_manager_balance` (`PlasmaVault._getGrossTotalAssets` adds
|
|
538
547
|
`IRewardsClaimManager.balanceOf()`, the vested rewards, when a manager is set;
|
|
@@ -990,6 +990,54 @@ and `log_index` was passed through as given (a hex string from a raw log); the e
|
|
|
990
990
|
These apply to every caller, type-checked or not. Changes described in full above
|
|
991
991
|
are listed with a link.
|
|
992
992
|
|
|
993
|
+
- **`vault validate` publishes one document.** In 3.x the CLI's `--json` output
|
|
994
|
+
and the MCP `vault_validate` tool returned two different shapes; both now
|
|
995
|
+
return `VaultValidationJson`, built by `build_vault_validation_json(validation,
|
|
996
|
+
chain)` (exported from `ipor_fusion` and `ipor_fusion.vault_info`):
|
|
997
|
+
- `findings` lists every check in order with its `check`, `severity` and
|
|
998
|
+
`message`. It replaces the CLI's `criticals` / `warnings` / `ok` string lists
|
|
999
|
+
and the MCP tool's `criticals` / `warnings` / `passed` lists; filter by
|
|
1000
|
+
`severity`.
|
|
1001
|
+
- `erc20` (`tokens`, `value_in_asset`, `market_cached_value`, `unpriced_tokens`)
|
|
1002
|
+
replaces the CLI's `erc20_balances`; `erc20.tokens` has the same entries.
|
|
1003
|
+
- `reconciliation`, `lending_health` and `asset` share their shapes with the
|
|
1004
|
+
`vault info` document. For the MCP tool this means `delta.percent` instead of
|
|
1005
|
+
`delta_percent`, amounts formatted with thousands separators and at most six
|
|
1006
|
+
decimals (`"14,912.465797"`; `raw` keeps the exact value) and the delta's
|
|
1007
|
+
`formatted` as its absolute value, as in `vault info`.
|
|
1008
|
+
- The MCP tool's output gains `block_timestamp`.
|
|
1009
|
+
- An ERC20 entry whose balance read failed keeps its `decimals` when they were
|
|
1010
|
+
read (in `vault info` too).
|
|
1011
|
+
- The MCP output is the builder's document key for key: an amount without a
|
|
1012
|
+
USD value and an ERC20 entry without a balance no longer gain `null` keys
|
|
1013
|
+
(`usd`, `price_usd`, ...) in either tool, `vault_info` included, and a zero
|
|
1014
|
+
USD delta without a price is `0.0`, not `0`.
|
|
1015
|
+
|
|
1016
|
+
- **A failed lending read is a warning, never a silent `ok`.** 3.x caught every
|
|
1017
|
+
exception in the lending-health readers and dropped the position, so a provider
|
|
1018
|
+
outage could leave no lending finding and an `ok` verdict. Now:
|
|
1019
|
+
- A position whose reads fail with a chain or transport error (revert, RPC,
|
|
1020
|
+
timeout, no or malformed data) becomes an `UnreadableLendingMarket` in
|
|
1021
|
+
`VaultLendingHealth.unreadable`.
|
|
1022
|
+
- Each unreadable position is a `lending_health` warning.
|
|
1023
|
+
- An Aave V3 market whose Pool could not be resolved is listed the same way
|
|
1024
|
+
instead of being skipped.
|
|
1025
|
+
- Any other exception propagates.
|
|
1026
|
+
- When the whole lending-health read or the unpriceable-token check fails with
|
|
1027
|
+
a revert, an RPC error or a timeout, `VaultData.failed_reads` names it and
|
|
1028
|
+
validation reports an `incomplete_read` warning. A transport failure (no
|
|
1029
|
+
connection) still aborts the fetch rather than return a snapshot.
|
|
1030
|
+
- A substrate the unpriceable-token check could not cover is named the same
|
|
1031
|
+
way (`unpriceable_priced_tokens: <what>`). Examples: a Morpho position whose
|
|
1032
|
+
read failed, or a reverting `asset()` / `getSilos()`.
|
|
1033
|
+
`fetch_unpriceable_priced_tokens` returns an `UnpriceableCheck` (`tokens`,
|
|
1034
|
+
`unread`) instead of a bare list.
|
|
1035
|
+
|
|
1036
|
+
The `lending_health` JSON block of `vault info` and `vault validate` carries
|
|
1037
|
+
`unreadable`, and a custom `VaultState` adds the `failed_reads` property. A
|
|
1038
|
+
position missing from the breakdown tables is shown as absent, while the
|
|
1039
|
+
checks it feeds report it.
|
|
1040
|
+
|
|
993
1041
|
- **More markets decode their substrates.** VELODROME_SUPERCHAIN (31, Gauge /
|
|
994
1042
|
Pool), AGUA_GLOBAL_CARRY (51, VAULT / ASSET), TERM_FINANCE (52, SERVICER address
|
|
995
1043
|
or COLLATERAL_TOKEN pair key), META_MORPHO_0001, MERKL and
|
|
@@ -275,6 +275,8 @@ from ipor_fusion.readers import (
|
|
|
275
275
|
RamsesV2Reader,
|
|
276
276
|
UniswapV3Position,
|
|
277
277
|
UniswapV3Reader,
|
|
278
|
+
UnpriceableCheck,
|
|
279
|
+
UnreadableLendingMarket,
|
|
278
280
|
VaultLendingHealth,
|
|
279
281
|
build_oracle_mapping,
|
|
280
282
|
fetch_unpriceable_priced_tokens,
|
|
@@ -366,7 +368,9 @@ from ipor_fusion.vault_info import (
|
|
|
366
368
|
DeploymentErrorJson,
|
|
367
369
|
DeploymentJson,
|
|
368
370
|
Erc20BalanceJson,
|
|
371
|
+
Erc20HoldingsJson,
|
|
369
372
|
FeesJson,
|
|
373
|
+
FindingJson,
|
|
370
374
|
FuseJson,
|
|
371
375
|
HealthCheckJson,
|
|
372
376
|
HighWaterMarkJson,
|
|
@@ -385,12 +389,15 @@ from ipor_fusion.vault_info import (
|
|
|
385
389
|
ReconciliationJson,
|
|
386
390
|
SharePriceJson,
|
|
387
391
|
SubstrateEntryJson,
|
|
392
|
+
UnreadableLendingMarketJson,
|
|
388
393
|
UsdAmountJson,
|
|
389
394
|
VaultAssetJson,
|
|
390
395
|
VaultInfoJson,
|
|
391
396
|
VaultLinksJson,
|
|
397
|
+
VaultValidationJson,
|
|
392
398
|
WithdrawManagerJson,
|
|
393
399
|
build_vault_info_json,
|
|
400
|
+
build_vault_validation_json,
|
|
394
401
|
)
|
|
395
402
|
|
|
396
403
|
__version__ = package_version()
|
|
@@ -631,6 +638,7 @@ __all__ = [
|
|
|
631
638
|
"HYPEREVM_CHAIN_ID",
|
|
632
639
|
"LendingMarketHealth",
|
|
633
640
|
"VaultLendingHealth",
|
|
641
|
+
"UnreadableLendingMarket",
|
|
634
642
|
"fetch_vault_lending_health",
|
|
635
643
|
"OracleAsset",
|
|
636
644
|
"OracleMapping",
|
|
@@ -651,6 +659,7 @@ __all__ = [
|
|
|
651
659
|
"build_oracle_mapping",
|
|
652
660
|
"OracleMappingReader",
|
|
653
661
|
"MiddlewarePricedToken",
|
|
662
|
+
"UnpriceableCheck",
|
|
654
663
|
"fetch_unpriceable_priced_tokens",
|
|
655
664
|
"PositionData",
|
|
656
665
|
"UniswapV3Reader",
|
|
@@ -701,6 +710,7 @@ __all__ = [
|
|
|
701
710
|
"HyperCorePerpMarketJson",
|
|
702
711
|
"HyperCoreSpotLegJson",
|
|
703
712
|
"LendingHealthJson",
|
|
713
|
+
"UnreadableLendingMarketJson",
|
|
704
714
|
"LendingMarketJson",
|
|
705
715
|
"ManagersJson",
|
|
706
716
|
"MorphoBreakdownJson",
|
|
@@ -713,6 +723,10 @@ __all__ = [
|
|
|
713
723
|
"UsdAmountJson",
|
|
714
724
|
"VaultAssetJson",
|
|
715
725
|
"VaultInfoJson",
|
|
726
|
+
"VaultValidationJson",
|
|
727
|
+
"FindingJson",
|
|
728
|
+
"Erc20HoldingsJson",
|
|
729
|
+
"build_vault_validation_json",
|
|
716
730
|
"VaultLinksJson",
|
|
717
731
|
"WithdrawManagerJson",
|
|
718
732
|
"MorphoApiError",
|
|
@@ -2,11 +2,9 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
import sys
|
|
5
|
-
from typing import TypedDict
|
|
6
5
|
|
|
7
6
|
import click
|
|
8
7
|
from web3 import Web3
|
|
9
|
-
from web3.types import Timestamp
|
|
10
8
|
|
|
11
9
|
from ipor_fusion.chains import CHAIN_NAMES
|
|
12
10
|
from ipor_fusion.cli.config_store import (
|
|
@@ -42,9 +40,8 @@ from ipor_fusion.errors import (
|
|
|
42
40
|
from ipor_fusion.readers.oracle_mapping import (
|
|
43
41
|
build_oracle_mapping,
|
|
44
42
|
)
|
|
45
|
-
from ipor_fusion.types import ChainId,
|
|
43
|
+
from ipor_fusion.types import ChainId, PlasmaVaultAddress
|
|
46
44
|
from ipor_fusion.validation import (
|
|
47
|
-
VaultValidation,
|
|
48
45
|
validate_vault,
|
|
49
46
|
)
|
|
50
47
|
from ipor_fusion.vault_data import (
|
|
@@ -52,43 +49,11 @@ from ipor_fusion.vault_data import (
|
|
|
52
49
|
fetch_vault_data,
|
|
53
50
|
)
|
|
54
51
|
from ipor_fusion.vault_info import (
|
|
55
|
-
Erc20BalanceJson,
|
|
56
|
-
LendingHealthJson,
|
|
57
|
-
ReconciliationJson,
|
|
58
|
-
VaultAssetJson,
|
|
59
|
-
_erc20_balances_json,
|
|
60
|
-
_lending_health_json,
|
|
61
|
-
_reconciliation_json,
|
|
62
52
|
_unix_to_iso,
|
|
53
|
+
build_vault_validation_json,
|
|
63
54
|
)
|
|
64
55
|
|
|
65
56
|
|
|
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
|
-
|
|
92
57
|
def _auto_save_vault(
|
|
93
58
|
cfg: FusionConfig,
|
|
94
59
|
vault_address: PlasmaVaultAddress,
|
|
@@ -296,7 +261,9 @@ def validate(
|
|
|
296
261
|
|
|
297
262
|
chain_label = CHAIN_NAMES.get(chain_id, str(chain_id))
|
|
298
263
|
if json_output:
|
|
299
|
-
click.echo(
|
|
264
|
+
click.echo(
|
|
265
|
+
json.dumps(build_vault_validation_json(validation, chain_label), indent=2)
|
|
266
|
+
)
|
|
300
267
|
else:
|
|
301
268
|
click.echo(f"Vault: {validation.vault}")
|
|
302
269
|
click.echo(f"Chain: {chain_label} (chain-id={chain_id})")
|
|
@@ -307,36 +274,6 @@ def validate(
|
|
|
307
274
|
sys.exit(1)
|
|
308
275
|
|
|
309
276
|
|
|
310
|
-
def _validation_json(validation: VaultValidation, chain_label: str) -> _ValidationJson:
|
|
311
|
-
return {
|
|
312
|
-
"vault": validation.vault,
|
|
313
|
-
"chain": chain_label,
|
|
314
|
-
"chain_id": validation.chain_id,
|
|
315
|
-
"block": validation.block_number,
|
|
316
|
-
"block_timestamp": validation.block_timestamp,
|
|
317
|
-
"block_timestamp_utc": _unix_to_iso(validation.block_timestamp),
|
|
318
|
-
"asset": {
|
|
319
|
-
"address": validation.asset,
|
|
320
|
-
"symbol": validation.asset_symbol,
|
|
321
|
-
"decimals": validation.asset_decimals,
|
|
322
|
-
"price_usd": validation.asset_price_usd,
|
|
323
|
-
},
|
|
324
|
-
"verdict": validation.verdict,
|
|
325
|
-
"criticals": list(validation.criticals),
|
|
326
|
-
"warnings": list(validation.warnings),
|
|
327
|
-
"ok": list(validation.ok),
|
|
328
|
-
"findings": [
|
|
329
|
-
{"check": f.check, "severity": f.severity, "message": f.message}
|
|
330
|
-
for f in validation.findings
|
|
331
|
-
],
|
|
332
|
-
"reconciliation": _reconciliation_json(
|
|
333
|
-
validation.reconciliation, validation.asset_decimals
|
|
334
|
-
),
|
|
335
|
-
"erc20_balances": _erc20_balances_json(validation),
|
|
336
|
-
"lending_health": _lending_health_json(validation.lending_health),
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
|
|
340
277
|
@vault.command("role-accounts")
|
|
341
278
|
@click.argument("vault_address", type=VAULT_ADDRESS)
|
|
342
279
|
@click.option(
|
{ipor_fusion-4.0.0.dev222 → ipor_fusion-4.0.0.dev234}/src/ipor_fusion/cli/vault_markets_view.py
RENAMED
|
@@ -95,6 +95,17 @@ def _print_lending_health(data: VaultData) -> None: # noqa: C901
|
|
|
95
95
|
if m.protocol == "aave_v4":
|
|
96
96
|
click.echo(f" spoke {m.substrate_id}:")
|
|
97
97
|
_print_health_lines(m, indent=" ")
|
|
98
|
+
_print_unreadable_health(lh)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _print_unreadable_health(lh: VaultLendingHealth | None) -> None:
|
|
102
|
+
for u in lh.unreadable if lh is not None else []:
|
|
103
|
+
where = f" {u.substrate_id}" if u.substrate_id else ""
|
|
104
|
+
click.secho(
|
|
105
|
+
f" {format_market_label(u.market_id)}: {u.protocol}{where} "
|
|
106
|
+
f"health unknown — {u.reason}",
|
|
107
|
+
fg="yellow",
|
|
108
|
+
)
|
|
98
109
|
|
|
99
110
|
|
|
100
111
|
def _index_lending_health(
|
|
@@ -33,8 +33,6 @@ Design notes:
|
|
|
33
33
|
|
|
34
34
|
from __future__ import annotations
|
|
35
35
|
|
|
36
|
-
from datetime import UTC, datetime
|
|
37
|
-
from decimal import Decimal
|
|
38
36
|
from typing import TYPE_CHECKING, Literal
|
|
39
37
|
|
|
40
38
|
from pydantic import (
|
|
@@ -62,19 +60,7 @@ from ipor_fusion.types import (
|
|
|
62
60
|
if TYPE_CHECKING:
|
|
63
61
|
from ipor_fusion.about import ChangelogEntry
|
|
64
62
|
from ipor_fusion.core.access import RoleAccount
|
|
65
|
-
from ipor_fusion.readers.lending_health import (
|
|
66
|
-
LendingMarketHealth as ReaderLendingMarketHealth,
|
|
67
|
-
)
|
|
68
|
-
from ipor_fusion.readers.lending_health import VaultLendingHealth
|
|
69
63
|
from ipor_fusion.readers.oracle_mapping import OracleMapping, OracleNode
|
|
70
|
-
from ipor_fusion.validation import (
|
|
71
|
-
Erc20Holding,
|
|
72
|
-
Erc20Holdings,
|
|
73
|
-
VaultValidation,
|
|
74
|
-
)
|
|
75
|
-
from ipor_fusion.validation import (
|
|
76
|
-
Reconciliation as ValidationReconciliation,
|
|
77
|
-
)
|
|
78
64
|
|
|
79
65
|
|
|
80
66
|
class _Base(BaseModel):
|
|
@@ -98,7 +84,7 @@ class _Sparse(_Base):
|
|
|
98
84
|
# ---------------------------------------------------------------------------
|
|
99
85
|
|
|
100
86
|
|
|
101
|
-
class Amount(
|
|
87
|
+
class Amount(_Sparse):
|
|
102
88
|
"""Token amount with both raw and formatted representations."""
|
|
103
89
|
|
|
104
90
|
raw: int | str = Field(description="Raw on-chain integer (or 'unlimited').")
|
|
@@ -382,7 +368,7 @@ class BalanceFuseEntry(_Base):
|
|
|
382
368
|
)
|
|
383
369
|
|
|
384
370
|
|
|
385
|
-
class ERC20Entry(
|
|
371
|
+
class ERC20Entry(_Sparse):
|
|
386
372
|
"""ERC-20 balance entry; field set varies by data availability."""
|
|
387
373
|
|
|
388
374
|
address: str
|
|
@@ -431,8 +417,20 @@ class LendingMarketHealth(_Base):
|
|
|
431
417
|
is_critical: bool
|
|
432
418
|
|
|
433
419
|
|
|
420
|
+
class UnreadableLendingMarket(_Base):
|
|
421
|
+
"""A lending position whose health could not be read: unknown, not
|
|
422
|
+
healthy."""
|
|
423
|
+
|
|
424
|
+
protocol: str
|
|
425
|
+
market_id: MarketId
|
|
426
|
+
market_name: str
|
|
427
|
+
substrate_id: str | None
|
|
428
|
+
reason: str
|
|
429
|
+
|
|
430
|
+
|
|
434
431
|
class LendingHealth(_Base):
|
|
435
432
|
markets: list[LendingMarketHealth]
|
|
433
|
+
unreadable: list[UnreadableLendingMarket] = Field(default_factory=list)
|
|
436
434
|
worst_ltv_usage_percent: float | None
|
|
437
435
|
|
|
438
436
|
|
|
@@ -758,242 +756,51 @@ class OracleMappingResponse(_Base):
|
|
|
758
756
|
# ---------------------------------------------------------------------------
|
|
759
757
|
|
|
760
758
|
|
|
761
|
-
def _formatted(raw: int, decimals: int) -> str:
|
|
762
|
-
return format(Decimal(raw).scaleb(-decimals).normalize(), "f") if raw else "0"
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
def _amount(raw: int, decimals: int, usd: float | None = None) -> Amount:
|
|
766
|
-
"""An Amount in vault_info's convention, the sign kept in `formatted`."""
|
|
767
|
-
return Amount(raw=raw, formatted=_formatted(raw, decimals), usd=usd)
|
|
768
|
-
|
|
769
|
-
|
|
770
759
|
class FindingModel(_Base):
|
|
771
760
|
check: Check
|
|
772
761
|
severity: Severity
|
|
773
762
|
message: str
|
|
774
763
|
|
|
775
764
|
|
|
776
|
-
class ReconciliationModel(_Base):
|
|
777
|
-
"""totalAssets against balance fuses, idle underlying and the rewards
|
|
778
|
-
claim manager's balance."""
|
|
779
|
-
|
|
780
|
-
balance_fuses_total: Amount
|
|
781
|
-
underlying_on_vault: Amount
|
|
782
|
-
rewards_manager_balance: Amount = Field(
|
|
783
|
-
description="RewardsClaimManager.balanceOf(), which totalAssets includes; "
|
|
784
|
-
"0 without a manager or when it could not be read."
|
|
785
|
-
)
|
|
786
|
-
management_fee_netted: Amount = Field(
|
|
787
|
-
description="Unrealized management fee subtracted from sum: totalAssets "
|
|
788
|
-
"nets it on vaults built before ipor-fusion #475; 0 otherwise."
|
|
789
|
-
)
|
|
790
|
-
erc20_direct_total: Amount = Field(
|
|
791
|
-
description="Informational: already valued by the ERC20_VAULT_BALANCE "
|
|
792
|
-
"balance fuse, never added to sum."
|
|
793
|
-
)
|
|
794
|
-
sum: Amount
|
|
795
|
-
on_chain_total_assets: Amount
|
|
796
|
-
delta: Amount
|
|
797
|
-
delta_percent: float
|
|
798
|
-
pending_withdrawals: Amount
|
|
799
|
-
implied_market_total: Amount
|
|
800
|
-
market_storage_divergence: int = Field(
|
|
801
|
-
description="balance_fuses_total minus implied_market_total, raw: "
|
|
802
|
-
"per-market caches drifting from the stored global total."
|
|
803
|
-
)
|
|
804
|
-
|
|
805
|
-
@classmethod
|
|
806
|
-
def from_reconciliation(
|
|
807
|
-
cls, rec: ValidationReconciliation, decimals: int
|
|
808
|
-
) -> ReconciliationModel:
|
|
809
|
-
def amount(raw: int, usd: float | None = None) -> Amount:
|
|
810
|
-
return _amount(raw, decimals, usd)
|
|
811
|
-
|
|
812
|
-
return cls(
|
|
813
|
-
balance_fuses_total=amount(
|
|
814
|
-
rec.balance_fuses_total, rec.balance_fuses_total_usd
|
|
815
|
-
),
|
|
816
|
-
underlying_on_vault=amount(
|
|
817
|
-
rec.underlying_on_vault, rec.underlying_on_vault_usd
|
|
818
|
-
),
|
|
819
|
-
rewards_manager_balance=amount(
|
|
820
|
-
rec.rewards_manager_balance, rec.rewards_manager_balance_usd
|
|
821
|
-
),
|
|
822
|
-
management_fee_netted=amount(
|
|
823
|
-
rec.management_fee_netted, rec.management_fee_netted_usd
|
|
824
|
-
),
|
|
825
|
-
erc20_direct_total=amount(
|
|
826
|
-
rec.erc20_direct_total, rec.erc20_direct_total_usd
|
|
827
|
-
),
|
|
828
|
-
sum=amount(rec.sum, rec.sum_usd),
|
|
829
|
-
on_chain_total_assets=amount(
|
|
830
|
-
rec.on_chain_total_assets, rec.on_chain_total_assets_usd
|
|
831
|
-
),
|
|
832
|
-
delta=amount(rec.delta, rec.delta_usd),
|
|
833
|
-
delta_percent=rec.delta_percent,
|
|
834
|
-
pending_withdrawals=amount(
|
|
835
|
-
rec.pending_withdrawals, rec.pending_withdrawals_usd
|
|
836
|
-
),
|
|
837
|
-
implied_market_total=amount(rec.implied_market_total),
|
|
838
|
-
market_storage_divergence=rec.market_storage_divergence,
|
|
839
|
-
)
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
class LendingMarketModel(_Base):
|
|
843
|
-
protocol: str
|
|
844
|
-
market_id: MarketId
|
|
845
|
-
market_name: str
|
|
846
|
-
substrate_id: str | None = Field(
|
|
847
|
-
description="0x-prefixed Morpho market id or Aave V4 Spoke; null for "
|
|
848
|
-
"Aave V3, whose health is account-level."
|
|
849
|
-
)
|
|
850
|
-
current_ltv: float | None
|
|
851
|
-
max_ltv: float
|
|
852
|
-
health_factor: float | None
|
|
853
|
-
total_collateral_usd: float | None
|
|
854
|
-
total_debt_usd: float | None
|
|
855
|
-
ltv_usage_percent: float | None
|
|
856
|
-
|
|
857
|
-
@classmethod
|
|
858
|
-
def from_market(cls, m: ReaderLendingMarketHealth) -> LendingMarketModel:
|
|
859
|
-
substrate_id = m.substrate_id
|
|
860
|
-
if substrate_id is not None and not substrate_id.startswith("0x"):
|
|
861
|
-
substrate_id = f"0x{substrate_id}"
|
|
862
|
-
return cls(
|
|
863
|
-
protocol=m.protocol,
|
|
864
|
-
market_id=m.market_id,
|
|
865
|
-
market_name=m.market_name,
|
|
866
|
-
substrate_id=substrate_id,
|
|
867
|
-
current_ltv=m.current_ltv,
|
|
868
|
-
max_ltv=m.max_ltv,
|
|
869
|
-
health_factor=m.health_factor,
|
|
870
|
-
total_collateral_usd=m.total_collateral_usd,
|
|
871
|
-
total_debt_usd=m.total_debt_usd,
|
|
872
|
-
ltv_usage_percent=m.ltv_usage_percent,
|
|
873
|
-
)
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
class LendingHealthModel(_Base):
|
|
877
|
-
markets: list[LendingMarketModel]
|
|
878
|
-
worst_ltv_usage_percent: float | None
|
|
879
|
-
|
|
880
|
-
@classmethod
|
|
881
|
-
def from_health(cls, health: VaultLendingHealth) -> LendingHealthModel:
|
|
882
|
-
return cls(
|
|
883
|
-
markets=[LendingMarketModel.from_market(m) for m in health.markets],
|
|
884
|
-
worst_ltv_usage_percent=health.worst_ltv_usage,
|
|
885
|
-
)
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
class Erc20HoldingModel(_Base):
|
|
889
|
-
address: str
|
|
890
|
-
symbol: str
|
|
891
|
-
decimals: int | None
|
|
892
|
-
balance: Amount | None
|
|
893
|
-
price_usd: float | None
|
|
894
|
-
usd_value: float | None
|
|
895
|
-
note: str
|
|
896
|
-
|
|
897
|
-
@classmethod
|
|
898
|
-
def from_holding(cls, token: Erc20Holding) -> Erc20HoldingModel:
|
|
899
|
-
balance = (
|
|
900
|
-
_amount(token.balance, token.decimals)
|
|
901
|
-
if token.balance is not None and token.decimals is not None
|
|
902
|
-
else None
|
|
903
|
-
)
|
|
904
|
-
return cls(
|
|
905
|
-
address=token.address,
|
|
906
|
-
symbol=token.symbol,
|
|
907
|
-
decimals=token.decimals,
|
|
908
|
-
balance=balance,
|
|
909
|
-
price_usd=token.price_usd,
|
|
910
|
-
usd_value=token.usd_value,
|
|
911
|
-
note=token.note,
|
|
912
|
-
)
|
|
913
|
-
|
|
914
|
-
|
|
915
765
|
class Erc20HoldingsModel(_Base):
|
|
916
|
-
tokens
|
|
766
|
+
"""The ERC20_VAULT_BALANCE tokens read directly."""
|
|
767
|
+
|
|
768
|
+
tokens: list[ERC20Entry]
|
|
917
769
|
value_in_asset: Amount
|
|
918
770
|
market_cached_value: Amount = Field(
|
|
919
771
|
description="What the ERC20_VAULT_BALANCE market last stored for "
|
|
920
772
|
"these tokens, in the asset."
|
|
921
773
|
)
|
|
922
|
-
unpriced_tokens: list[str]
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
def from_holdings(cls, erc20: Erc20Holdings, decimals: int) -> Erc20HoldingsModel:
|
|
926
|
-
return cls(
|
|
927
|
-
tokens=[Erc20HoldingModel.from_holding(t) for t in erc20.tokens],
|
|
928
|
-
value_in_asset=_amount(erc20.value_in_asset, decimals, erc20.value_usd),
|
|
929
|
-
market_cached_value=_amount(erc20.market_cached_value, decimals),
|
|
930
|
-
unpriced_tokens=list(erc20.unpriced_tokens),
|
|
931
|
-
)
|
|
774
|
+
unpriced_tokens: list[str] = Field(
|
|
775
|
+
description="Held tokens that could not be valued, as 'address (symbol)'."
|
|
776
|
+
)
|
|
932
777
|
|
|
933
778
|
|
|
934
779
|
class VaultValidationResponse(_Base):
|
|
935
|
-
"""Health verdict of one Plasma Vault at one block
|
|
780
|
+
"""Health verdict of one Plasma Vault at one block; the same document as
|
|
781
|
+
``fusion vault validate --json``."""
|
|
936
782
|
|
|
937
783
|
vault: str
|
|
938
784
|
chain: str
|
|
939
785
|
chain_id: ChainId
|
|
940
786
|
block: int
|
|
787
|
+
block_timestamp: int
|
|
941
788
|
block_timestamp_utc: str
|
|
942
789
|
asset: AssetInfo
|
|
943
790
|
verdict: Verdict = Field(
|
|
944
791
|
description="Worst severity found: critical if any critical finding, "
|
|
945
792
|
"else warning if any warning, else ok."
|
|
946
793
|
)
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
passed: list[FindingModel] = Field(
|
|
950
|
-
description="Checks that ran and found nothing wrong."
|
|
794
|
+
findings: list[FindingModel] = Field(
|
|
795
|
+
description="Every check in the order it ran, ok ones included."
|
|
951
796
|
)
|
|
952
|
-
reconciliation:
|
|
953
|
-
|
|
797
|
+
reconciliation: Reconciliation
|
|
798
|
+
erc20: Erc20HoldingsModel
|
|
799
|
+
lending_health: LendingHealth | None = Field(
|
|
954
800
|
description="LTV and health factor per lending market (Morpho, Aave "
|
|
955
|
-
"V3/V4); null when the vault
|
|
801
|
+
"V3/V4) and the positions that could not be read; null when the vault "
|
|
802
|
+
"has no lending position."
|
|
956
803
|
)
|
|
957
|
-
erc20: Erc20HoldingsModel
|
|
958
|
-
|
|
959
|
-
@classmethod
|
|
960
|
-
def from_validation(cls, v: VaultValidation, chain: str) -> VaultValidationResponse:
|
|
961
|
-
def by(severity: Severity) -> list[FindingModel]:
|
|
962
|
-
return [
|
|
963
|
-
FindingModel(check=f.check, severity=f.severity, message=f.message)
|
|
964
|
-
for f in v.findings
|
|
965
|
-
if f.severity == severity
|
|
966
|
-
]
|
|
967
|
-
|
|
968
|
-
health = v.lending_health
|
|
969
|
-
return cls(
|
|
970
|
-
vault=v.vault,
|
|
971
|
-
chain=chain,
|
|
972
|
-
chain_id=v.chain_id,
|
|
973
|
-
block=v.block_number,
|
|
974
|
-
block_timestamp_utc=datetime.fromtimestamp(
|
|
975
|
-
v.block_timestamp, tz=UTC
|
|
976
|
-
).strftime("%Y-%m-%dT%H:%M:%SZ"),
|
|
977
|
-
asset=AssetInfo(
|
|
978
|
-
address=v.asset,
|
|
979
|
-
symbol=v.asset_symbol,
|
|
980
|
-
decimals=v.asset_decimals,
|
|
981
|
-
price_usd=v.asset_price_usd,
|
|
982
|
-
),
|
|
983
|
-
verdict=v.verdict,
|
|
984
|
-
criticals=by("critical"),
|
|
985
|
-
warnings=by("warning"),
|
|
986
|
-
passed=by("ok"),
|
|
987
|
-
reconciliation=ReconciliationModel.from_reconciliation(
|
|
988
|
-
v.reconciliation, v.asset_decimals
|
|
989
|
-
),
|
|
990
|
-
lending_health=(
|
|
991
|
-
LendingHealthModel.from_health(health)
|
|
992
|
-
if health is not None and health.has_lending_positions
|
|
993
|
-
else None
|
|
994
|
-
),
|
|
995
|
-
erc20=Erc20HoldingsModel.from_holdings(v.erc20, v.asset_decimals),
|
|
996
|
-
)
|
|
997
804
|
|
|
998
805
|
|
|
999
806
|
# ---------------------------------------------------------------------------
|
|
@@ -65,7 +65,7 @@ from ipor_fusion.vault_data import (
|
|
|
65
65
|
fetch_deployment_info,
|
|
66
66
|
fetch_vault_data,
|
|
67
67
|
)
|
|
68
|
-
from ipor_fusion.vault_info import build_vault_info_json
|
|
68
|
+
from ipor_fusion.vault_info import build_vault_info_json, build_vault_validation_json
|
|
69
69
|
|
|
70
70
|
# chain_id default: detect the chain from the saved vault or the single provider.
|
|
71
71
|
_AUTO_CHAIN = ChainId(0)
|
|
@@ -246,8 +246,10 @@ def vault_validate(
|
|
|
246
246
|
resolve_access_manager(ctx, checksum)
|
|
247
247
|
|
|
248
248
|
validation = validate_vault(ctx, checksum, block=effective_block, metadata=True)
|
|
249
|
-
return VaultValidationResponse.
|
|
250
|
-
|
|
249
|
+
return VaultValidationResponse.model_validate(
|
|
250
|
+
build_vault_validation_json(
|
|
251
|
+
validation, CHAIN_NAMES.get(chain_id, str(chain_id))
|
|
252
|
+
)
|
|
251
253
|
)
|
|
252
254
|
|
|
253
255
|
|
|
@@ -17,6 +17,7 @@ from ipor_fusion.readers.hypercore import (
|
|
|
17
17
|
)
|
|
18
18
|
from ipor_fusion.readers.lending_health import (
|
|
19
19
|
LendingMarketHealth,
|
|
20
|
+
UnreadableLendingMarket,
|
|
20
21
|
VaultLendingHealth,
|
|
21
22
|
fetch_vault_lending_health,
|
|
22
23
|
)
|
|
@@ -56,6 +57,7 @@ from ipor_fusion.readers.ramses_v2 import RamsesV2Position, RamsesV2Reader
|
|
|
56
57
|
from ipor_fusion.readers.uniswap_v3 import UniswapV3Position, UniswapV3Reader
|
|
57
58
|
from ipor_fusion.readers.unpriceable import (
|
|
58
59
|
MiddlewarePricedToken,
|
|
60
|
+
UnpriceableCheck,
|
|
59
61
|
fetch_unpriceable_priced_tokens,
|
|
60
62
|
)
|
|
61
63
|
|
|
@@ -80,6 +82,7 @@ __all__ = [
|
|
|
80
82
|
"HYPEREVM_CHAIN_ID",
|
|
81
83
|
"LendingMarketHealth",
|
|
82
84
|
"VaultLendingHealth",
|
|
85
|
+
"UnreadableLendingMarket",
|
|
83
86
|
"fetch_vault_lending_health",
|
|
84
87
|
"OracleAsset",
|
|
85
88
|
"OracleMapping",
|
|
@@ -100,6 +103,7 @@ __all__ = [
|
|
|
100
103
|
"build_oracle_mapping",
|
|
101
104
|
"OracleMappingReader",
|
|
102
105
|
"MiddlewarePricedToken",
|
|
106
|
+
"UnpriceableCheck",
|
|
103
107
|
"fetch_unpriceable_priced_tokens",
|
|
104
108
|
"PositionData",
|
|
105
109
|
"UniswapV3Reader",
|