ipor-fusion 4.0.0.dev30__tar.gz → 4.0.0.dev32__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.dev30 → ipor_fusion-4.0.0.dev32}/AGENTS.md +3 -1
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/__init__.py +2 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/market_cmd.py +18 -26
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/market_info.py +3 -3
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/mcp/server.py +4 -9
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/morpho_api.py +20 -13
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/lending_health.py +8 -4
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/types.py +16 -1
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/vault_data.py +7 -4
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_market_morpho_blue.py +3 -1
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/typed_client/consumer.py +3 -1
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/README.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/crosschain/base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/crosschain/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/crosschain/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/uv.lock +0 -0
|
@@ -285,7 +285,9 @@ or examples.
|
|
|
285
285
|
`MarketId`, ...) name the unit, and nothing scales by decimals.
|
|
286
286
|
- Ids and addresses are nominal in every signature: `ChainId`, `MarketId` (each
|
|
287
287
|
`IporFusionMarkets` member is one), `RoleId | Roles`, `ChecksumAddress`;
|
|
288
|
-
`HexAddress` only for the lowercase addresses decoded from substrates
|
|
288
|
+
`HexAddress` only for the lowercase addresses decoded from substrates;
|
|
289
|
+
`MorphoBlueMarketId` is always `0x` + 64 lowercase hex, built by
|
|
290
|
+
`parse_morpho_market_id`. Raw input
|
|
289
291
|
is parsed once at the boundary (click param types, MCP tools, the user config).
|
|
290
292
|
`src/`, `examples/` and `tests/typed_client/` are checked with
|
|
291
293
|
`reportArgumentType` on, so a bare `int`/`str` passed for one fails pyright; the
|
|
@@ -336,6 +336,7 @@ from ipor_fusion.types import (
|
|
|
336
336
|
Tick,
|
|
337
337
|
TokenId,
|
|
338
338
|
TransferId,
|
|
339
|
+
parse_morpho_market_id,
|
|
339
340
|
)
|
|
340
341
|
from ipor_fusion.validation import (
|
|
341
342
|
Erc20Holding,
|
|
@@ -605,6 +606,7 @@ __all__ = [
|
|
|
605
606
|
"RoleId",
|
|
606
607
|
"ChainId",
|
|
607
608
|
"MorphoBlueMarketId",
|
|
609
|
+
"parse_morpho_market_id",
|
|
608
610
|
"AssetId",
|
|
609
611
|
"CommandId",
|
|
610
612
|
"DeploymentRequestId",
|
|
@@ -42,7 +42,7 @@ from ipor_fusion.readers.morpho import (
|
|
|
42
42
|
MorphoReader,
|
|
43
43
|
morpho_blue_address,
|
|
44
44
|
)
|
|
45
|
-
from ipor_fusion.types import ChainId, MorphoBlueMarketId
|
|
45
|
+
from ipor_fusion.types import ChainId, MorphoBlueMarketId, parse_morpho_market_id
|
|
46
46
|
from ipor_fusion.vault_info import BLOCK_EXPLORER_URLS
|
|
47
47
|
|
|
48
48
|
|
|
@@ -54,12 +54,10 @@ class MarketIdType(click.ParamType):
|
|
|
54
54
|
def convert(self, value, param, ctx): # type: ignore[override]
|
|
55
55
|
if not isinstance(value, str):
|
|
56
56
|
self.fail(f"expected string, got {type(value).__name__}", param, ctx)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
)
|
|
62
|
-
return raw.lower()
|
|
57
|
+
try:
|
|
58
|
+
return parse_morpho_market_id(value)
|
|
59
|
+
except ValueError as exc:
|
|
60
|
+
self.fail(str(exc), param, ctx)
|
|
63
61
|
|
|
64
62
|
|
|
65
63
|
MARKET_ID = MarketIdType()
|
|
@@ -106,7 +104,7 @@ def market() -> None:
|
|
|
106
104
|
help="Emit machine-readable JSON instead of a table.",
|
|
107
105
|
)
|
|
108
106
|
def morpho_blue(
|
|
109
|
-
market_id:
|
|
107
|
+
market_id: MorphoBlueMarketId,
|
|
110
108
|
chain_id: ChainId,
|
|
111
109
|
block: int | None,
|
|
112
110
|
no_api: bool,
|
|
@@ -127,7 +125,7 @@ def morpho_blue(
|
|
|
127
125
|
if block is not None:
|
|
128
126
|
ctx.default_block = block
|
|
129
127
|
reader = MorphoReader(ctx, morpho_blue_address(chain_id))
|
|
130
|
-
mid =
|
|
128
|
+
mid = market_id
|
|
131
129
|
params, state = reader.require_market(mid)
|
|
132
130
|
rates = reader.rates_from(state, params)
|
|
133
131
|
|
|
@@ -171,7 +169,7 @@ def morpho_blue(
|
|
|
171
169
|
|
|
172
170
|
|
|
173
171
|
def _print_market(
|
|
174
|
-
market_id:
|
|
172
|
+
market_id: MorphoBlueMarketId,
|
|
175
173
|
chain_id: ChainId,
|
|
176
174
|
params: MorphoMarketParams,
|
|
177
175
|
state: MorphoMarket,
|
|
@@ -181,11 +179,11 @@ def _print_market(
|
|
|
181
179
|
chain_name = CHAIN_NAMES.get(chain_id, str(chain_id))
|
|
182
180
|
explorer = BLOCK_EXPLORER_URLS.get(chain_id, "")
|
|
183
181
|
liquidity = state.total_supply_assets - state.total_borrow_assets
|
|
184
|
-
click.secho(f"Morpho Blue market
|
|
182
|
+
click.secho(f"Morpho Blue market {market_id}", bold=True)
|
|
185
183
|
click.echo(f" Chain: {chain_name} (id {chain_id})")
|
|
186
184
|
if explorer:
|
|
187
185
|
click.echo(
|
|
188
|
-
f" App: https://app.morpho.org/{chain_name}/market/
|
|
186
|
+
f" App: https://app.morpho.org/{chain_name}/market/{market_id}"
|
|
189
187
|
)
|
|
190
188
|
click.echo(f" Loan token: {params.loan_token}")
|
|
191
189
|
click.echo(f" Collateral: {params.collateral_token}")
|
|
@@ -332,7 +330,7 @@ def _print_reallocate_hint(params: MorphoMarketParams) -> None:
|
|
|
332
330
|
@click.option(
|
|
333
331
|
"--market",
|
|
334
332
|
"market_filter",
|
|
335
|
-
type=
|
|
333
|
+
type=MARKET_ID,
|
|
336
334
|
default=None,
|
|
337
335
|
help="Filter caps/allocations to a single Morpho Blue market ID.",
|
|
338
336
|
)
|
|
@@ -346,7 +344,7 @@ def _print_reallocate_hint(params: MorphoMarketParams) -> None:
|
|
|
346
344
|
def meta_morpho(
|
|
347
345
|
vault_address: ChecksumAddress,
|
|
348
346
|
chain_id: ChainId,
|
|
349
|
-
market_filter:
|
|
347
|
+
market_filter: MorphoBlueMarketId | None,
|
|
350
348
|
json_output: bool,
|
|
351
349
|
) -> None:
|
|
352
350
|
"""Inspect a MetaMorpho V1 or Morpho Vault V2 by address.
|
|
@@ -361,22 +359,18 @@ def meta_morpho(
|
|
|
361
359
|
except MorphoApiError as exc:
|
|
362
360
|
raise click.UsageError(str(exc)) from exc
|
|
363
361
|
|
|
364
|
-
market_filter_norm = (
|
|
365
|
-
("0x" + market_filter.removeprefix("0x").lower()) if market_filter else None
|
|
366
|
-
)
|
|
367
|
-
|
|
368
362
|
if json_output:
|
|
369
363
|
click.echo(json_lib.dumps(build_meta_morpho_json(info, chain_id), indent=2))
|
|
370
364
|
return
|
|
371
365
|
|
|
372
366
|
if isinstance(info, VaultV2Info):
|
|
373
|
-
_print_vault_v2(info, chain_id,
|
|
367
|
+
_print_vault_v2(info, chain_id, market_filter)
|
|
374
368
|
else:
|
|
375
|
-
_print_vault_v1(info, chain_id,
|
|
369
|
+
_print_vault_v1(info, chain_id, market_filter)
|
|
376
370
|
|
|
377
371
|
|
|
378
372
|
def _print_vault_v2(
|
|
379
|
-
vault: VaultV2Info, chain_id: ChainId, market_filter:
|
|
373
|
+
vault: VaultV2Info, chain_id: ChainId, market_filter: MorphoBlueMarketId | None
|
|
380
374
|
) -> None:
|
|
381
375
|
chain_name = CHAIN_NAMES.get(chain_id, str(chain_id))
|
|
382
376
|
click.secho(f"Morpho Vault V2 — {vault.name} ({vault.symbol})", bold=True)
|
|
@@ -433,9 +427,7 @@ def _print_vault_v2(
|
|
|
433
427
|
market_caps = [c for c in vault.caps if c.cap_type == "MarketV1"]
|
|
434
428
|
other_caps = [c for c in vault.caps if c.cap_type != "MarketV1"]
|
|
435
429
|
if market_filter:
|
|
436
|
-
market_caps = [
|
|
437
|
-
c for c in market_caps if (c.market_id or "").lower() == market_filter
|
|
438
|
-
]
|
|
430
|
+
market_caps = [c for c in market_caps if c.market_id == market_filter]
|
|
439
431
|
|
|
440
432
|
click.secho(f"Morpho Blue market caps ({len(market_caps)}):", bold=True)
|
|
441
433
|
_print_market_caps(market_caps, vault.asset_symbol, vault.asset_decimals)
|
|
@@ -508,7 +500,7 @@ def _print_other_caps(
|
|
|
508
500
|
|
|
509
501
|
|
|
510
502
|
def _print_vault_v1(
|
|
511
|
-
vault: VaultV1Info, chain_id: ChainId, market_filter:
|
|
503
|
+
vault: VaultV1Info, chain_id: ChainId, market_filter: MorphoBlueMarketId | None
|
|
512
504
|
) -> None:
|
|
513
505
|
chain_name = CHAIN_NAMES.get(chain_id, str(chain_id))
|
|
514
506
|
public_allocator = PUBLIC_ALLOCATOR_ADDRESSES.get(chain_id)
|
|
@@ -552,7 +544,7 @@ def _print_vault_v1(
|
|
|
552
544
|
|
|
553
545
|
allocations = vault.allocations
|
|
554
546
|
if market_filter:
|
|
555
|
-
allocations = [a for a in allocations if a.market_id
|
|
547
|
+
allocations = [a for a in allocations if a.market_id == market_filter]
|
|
556
548
|
click.secho(f"Allocations ({len(allocations)}):", bold=True)
|
|
557
549
|
if not allocations:
|
|
558
550
|
click.echo(" (none)")
|
|
@@ -17,11 +17,11 @@ from ipor_fusion.readers.morpho import (
|
|
|
17
17
|
MorphoMarketParams,
|
|
18
18
|
MorphoMarketRates,
|
|
19
19
|
)
|
|
20
|
-
from ipor_fusion.types import ChainId
|
|
20
|
+
from ipor_fusion.types import ChainId, MorphoBlueMarketId
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def build_morpho_blue_market_json(
|
|
24
|
-
market_id:
|
|
24
|
+
market_id: MorphoBlueMarketId,
|
|
25
25
|
chain_id: ChainId,
|
|
26
26
|
params: MorphoMarketParams,
|
|
27
27
|
state: MorphoMarket,
|
|
@@ -36,7 +36,7 @@ def build_morpho_blue_market_json(
|
|
|
36
36
|
given, or ``api_error`` when that lookup failed. ``market_id`` is the
|
|
37
37
|
64-hex-char id without ``0x``."""
|
|
38
38
|
out: dict = {
|
|
39
|
-
"market_id":
|
|
39
|
+
"market_id": market_id,
|
|
40
40
|
"chain_id": chain_id,
|
|
41
41
|
"public_allocator": public_allocator,
|
|
42
42
|
"market_params": {
|
|
@@ -55,7 +55,7 @@ from ipor_fusion.morpho_api import (
|
|
|
55
55
|
)
|
|
56
56
|
from ipor_fusion.readers.morpho import MorphoReader, morpho_blue_address
|
|
57
57
|
from ipor_fusion.readers.oracle_mapping import build_oracle_mapping
|
|
58
|
-
from ipor_fusion.types import ChainId,
|
|
58
|
+
from ipor_fusion.types import ChainId, parse_morpho_market_id
|
|
59
59
|
from ipor_fusion.validation import validate_vault
|
|
60
60
|
from ipor_fusion.vault_data import (
|
|
61
61
|
fetch_deployment_info,
|
|
@@ -580,16 +580,11 @@ def market_morpho_blue(
|
|
|
580
580
|
block_number: Block number for on-chain reads (latest if 0).
|
|
581
581
|
no_api: Skip Morpho API call (no vault discovery / PublicAllocator info).
|
|
582
582
|
"""
|
|
583
|
-
|
|
584
|
-
if len(raw) != 64 or not all(c in "0123456789abcdef" for c in raw):
|
|
585
|
-
raise ValueError(
|
|
586
|
-
f"invalid Morpho market ID (expected 32-byte hex): {market_id}"
|
|
587
|
-
)
|
|
583
|
+
mid = parse_morpho_market_id(market_id)
|
|
588
584
|
|
|
589
585
|
cfg = load_config()
|
|
590
586
|
ctx, _ = _build_ctx(cfg, chain_id, block_number)
|
|
591
587
|
reader = MorphoReader(ctx, morpho_blue_address(chain_id))
|
|
592
|
-
mid = MorphoBlueMarketId(raw)
|
|
593
588
|
params, state = reader.require_market(mid)
|
|
594
589
|
rates = reader.rates_from(state, params)
|
|
595
590
|
|
|
@@ -597,13 +592,13 @@ def market_morpho_blue(
|
|
|
597
592
|
api_error: str | None = None
|
|
598
593
|
if not no_api:
|
|
599
594
|
try:
|
|
600
|
-
api_market = fetch_market(
|
|
595
|
+
api_market = fetch_market(mid, chain_id)
|
|
601
596
|
except MorphoApiError as exc:
|
|
602
597
|
api_error = str(exc)
|
|
603
598
|
|
|
604
599
|
public_allocator = PUBLIC_ALLOCATOR_ADDRESSES.get(chain_id)
|
|
605
600
|
payload = build_morpho_blue_market_json(
|
|
606
|
-
|
|
601
|
+
mid, chain_id, params, state, rates, api_market, api_error, public_allocator
|
|
607
602
|
)
|
|
608
603
|
return MorphoBlueMarketResponse.model_validate(payload)
|
|
609
604
|
|
|
@@ -17,7 +17,7 @@ from eth_abi import decode, encode
|
|
|
17
17
|
from eth_utils import keccak
|
|
18
18
|
from web3 import Web3
|
|
19
19
|
|
|
20
|
-
from ipor_fusion.types import ChainId
|
|
20
|
+
from ipor_fusion.types import ChainId, MorphoBlueMarketId, parse_morpho_market_id
|
|
21
21
|
|
|
22
22
|
MORPHO_API_URL = "https://blue-api.morpho.org/graphql"
|
|
23
23
|
|
|
@@ -113,7 +113,7 @@ class VaultAllocation:
|
|
|
113
113
|
class MorphoApiMarket:
|
|
114
114
|
"""Snapshot of a Morpho Blue market plus the vaults supplying to it."""
|
|
115
115
|
|
|
116
|
-
market_id:
|
|
116
|
+
market_id: MorphoBlueMarketId
|
|
117
117
|
lltv: int
|
|
118
118
|
loan_token: str
|
|
119
119
|
loan_symbol: str
|
|
@@ -139,7 +139,7 @@ class MorphoApiError(RuntimeError):
|
|
|
139
139
|
|
|
140
140
|
|
|
141
141
|
def fetch_market(
|
|
142
|
-
market_id:
|
|
142
|
+
market_id: MorphoBlueMarketId, chain_id: ChainId, *, timeout: float = 10.0
|
|
143
143
|
) -> MorphoApiMarket:
|
|
144
144
|
"""Fetch a Morpho Blue market with its supplying vaults from the public API.
|
|
145
145
|
|
|
@@ -147,8 +147,6 @@ def fetch_market(
|
|
|
147
147
|
ID (1 = mainnet, 8453 = base, ...). Raises `MorphoApiError` on network failure
|
|
148
148
|
or if the market is not indexed.
|
|
149
149
|
"""
|
|
150
|
-
if not market_id.startswith("0x"):
|
|
151
|
-
market_id = "0x" + market_id
|
|
152
150
|
payload = json.dumps(
|
|
153
151
|
{
|
|
154
152
|
"query": _MARKET_QUERY,
|
|
@@ -182,7 +180,7 @@ def fetch_market(
|
|
|
182
180
|
def _parse_market(raw: dict) -> MorphoApiMarket:
|
|
183
181
|
state = raw.get("state") or {}
|
|
184
182
|
return MorphoApiMarket(
|
|
185
|
-
market_id=raw
|
|
183
|
+
market_id=_api_market_id(raw.get("marketId")),
|
|
186
184
|
lltv=int(raw["lltv"]),
|
|
187
185
|
loan_token=raw["loanAsset"]["address"],
|
|
188
186
|
loan_symbol=raw["loanAsset"]["symbol"],
|
|
@@ -282,7 +280,7 @@ class VaultV2Cap:
|
|
|
282
280
|
absolute_cap: int
|
|
283
281
|
relative_cap_wad: int
|
|
284
282
|
allocation: int
|
|
285
|
-
market_id:
|
|
283
|
+
market_id: MorphoBlueMarketId | None
|
|
286
284
|
loan_token: str | None
|
|
287
285
|
collateral_token: str | None
|
|
288
286
|
oracle: str | None
|
|
@@ -337,7 +335,7 @@ class VaultV2Info:
|
|
|
337
335
|
class VaultV1MarketAllocation:
|
|
338
336
|
"""A MetaMorpho V1 allocation entry."""
|
|
339
337
|
|
|
340
|
-
market_id:
|
|
338
|
+
market_id: MorphoBlueMarketId
|
|
341
339
|
lltv: int
|
|
342
340
|
loan_symbol: str
|
|
343
341
|
loan_decimals: int
|
|
@@ -550,9 +548,18 @@ def _decode_market_v1_id_data(
|
|
|
550
548
|
)
|
|
551
549
|
|
|
552
550
|
|
|
551
|
+
def _api_market_id(value: object) -> MorphoBlueMarketId:
|
|
552
|
+
try:
|
|
553
|
+
return parse_morpho_market_id(str(value or ""))
|
|
554
|
+
except ValueError as exc:
|
|
555
|
+
raise MorphoApiError(
|
|
556
|
+
f"Morpho API returned an invalid market id: {value!r}"
|
|
557
|
+
) from exc
|
|
558
|
+
|
|
559
|
+
|
|
553
560
|
def _morpho_blue_market_id(
|
|
554
561
|
loan: str, collateral: str, oracle: str, irm: str, lltv: int
|
|
555
|
-
) ->
|
|
562
|
+
) -> MorphoBlueMarketId:
|
|
556
563
|
"""Compute a Morpho Blue market unique key from MarketParams.
|
|
557
564
|
|
|
558
565
|
`marketId = keccak256(abi.encode(loanToken, collateralToken, oracle, irm, lltv))`
|
|
@@ -562,7 +569,7 @@ def _morpho_blue_market_id(
|
|
|
562
569
|
["address", "address", "address", "address", "uint256"],
|
|
563
570
|
[loan, collateral, oracle, irm, lltv],
|
|
564
571
|
)
|
|
565
|
-
return
|
|
572
|
+
return parse_morpho_market_id(keccak(encoded))
|
|
566
573
|
|
|
567
574
|
|
|
568
575
|
def _parse_vault_v1(raw: dict) -> VaultV1Info:
|
|
@@ -576,7 +583,7 @@ def _parse_vault_v1(raw: dict) -> VaultV1Info:
|
|
|
576
583
|
collat_asset = market.get("collateralAsset") or {}
|
|
577
584
|
allocations.append(
|
|
578
585
|
VaultV1MarketAllocation(
|
|
579
|
-
market_id=market.get("marketId")
|
|
586
|
+
market_id=_api_market_id(market.get("marketId")),
|
|
580
587
|
lltv=int(market.get("lltv") or 0),
|
|
581
588
|
loan_symbol=loan_asset.get("symbol") or "",
|
|
582
589
|
loan_decimals=int(loan_asset.get("decimals") or 0),
|
|
@@ -626,14 +633,14 @@ def _parse_vault_v1(raw: dict) -> VaultV1Info:
|
|
|
626
633
|
)
|
|
627
634
|
|
|
628
635
|
|
|
629
|
-
def _parse_vault(raw: dict, market_id:
|
|
636
|
+
def _parse_vault(raw: dict, market_id: MorphoBlueMarketId) -> VaultAllocation:
|
|
630
637
|
asset = raw.get("asset") or {}
|
|
631
638
|
state = raw.get("state") or {}
|
|
632
639
|
allocation_for_market: dict = next(
|
|
633
640
|
(
|
|
634
641
|
a
|
|
635
642
|
for a in (state.get("allocation") or [])
|
|
636
|
-
if (a.get("market") or {}).get("marketId", "").lower() == market_id
|
|
643
|
+
if (a.get("market") or {}).get("marketId", "").lower() == market_id
|
|
637
644
|
),
|
|
638
645
|
{},
|
|
639
646
|
)
|
{ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/readers/lending_health.py
RENAMED
|
@@ -29,7 +29,12 @@ from ipor_fusion.readers.morpho import (
|
|
|
29
29
|
morpho_blue_address,
|
|
30
30
|
)
|
|
31
31
|
from ipor_fusion.substrates import decode_substrate, market_name
|
|
32
|
-
from ipor_fusion.types import
|
|
32
|
+
from ipor_fusion.types import (
|
|
33
|
+
ChainId,
|
|
34
|
+
MarketId,
|
|
35
|
+
MorphoBlueMarketId,
|
|
36
|
+
parse_morpho_market_id,
|
|
37
|
+
)
|
|
33
38
|
|
|
34
39
|
_logger = logging.getLogger(__name__)
|
|
35
40
|
|
|
@@ -374,9 +379,8 @@ def _collect_lending_markets(
|
|
|
374
379
|
if mid in MORPHO_MARKET_IDS:
|
|
375
380
|
substrates = market_substrates.get(mid, [])
|
|
376
381
|
for sub in substrates:
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
markets.morpho.append((mid, name, MorphoBlueMarketId(hex_str)))
|
|
382
|
+
if len(sub) == 32:
|
|
383
|
+
markets.morpho.append((mid, name, parse_morpho_market_id(sub)))
|
|
380
384
|
elif mid in AAVE_V3_MARKET_IDS:
|
|
381
385
|
if aave_pool := aave_pools.get(mid):
|
|
382
386
|
markets.aave_v3.append((mid, name, aave_pool))
|
|
@@ -13,7 +13,9 @@ Tick = NewType("Tick", int)
|
|
|
13
13
|
Liquidity = NewType("Liquidity", int)
|
|
14
14
|
RoleId = NewType("RoleId", int)
|
|
15
15
|
ChainId = NewType("ChainId", int)
|
|
16
|
-
#
|
|
16
|
+
# A Morpho Blue market id (bytes32) in its canonical spelling: "0x" and 64
|
|
17
|
+
# lowercase hex digits, as the Morpho API reports it. Build one with
|
|
18
|
+
# parse_morpho_market_id.
|
|
17
19
|
MorphoBlueMarketId = NewType("MorphoBlueMarketId", str)
|
|
18
20
|
# Crosschain identifiers (bytes32 unless noted), named after the contracts' fields.
|
|
19
21
|
CommandId = NewType("CommandId", bytes)
|
|
@@ -98,3 +100,16 @@ Period.MINUTE = Period(60 * Period.SECOND)
|
|
|
98
100
|
Period.HOUR = Period(60 * Period.MINUTE)
|
|
99
101
|
Period.DAY = Period(24 * Period.HOUR)
|
|
100
102
|
Period.WEEK = Period(7 * Period.DAY)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def parse_morpho_market_id(value: str | bytes) -> MorphoBlueMarketId:
|
|
106
|
+
"""A Morpho Blue market id from 32 raw bytes or from hex with or without
|
|
107
|
+
``0x``, in any case; raises ``ValueError`` on anything else."""
|
|
108
|
+
if isinstance(value, bytes):
|
|
109
|
+
if len(value) != 32:
|
|
110
|
+
raise ValueError(f"invalid Morpho market ID (expected 32 bytes): {value!r}")
|
|
111
|
+
return MorphoBlueMarketId("0x" + value.hex())
|
|
112
|
+
digits = value.strip().removeprefix("0x").removeprefix("0X").lower()
|
|
113
|
+
if len(digits) != 64 or any(c not in "0123456789abcdef" for c in digits):
|
|
114
|
+
raise ValueError(f"invalid Morpho market ID (expected 32-byte hex): {value}")
|
|
115
|
+
return MorphoBlueMarketId("0x" + digits)
|
|
@@ -78,7 +78,12 @@ from ipor_fusion.readers.unpriceable import (
|
|
|
78
78
|
MiddlewarePricedToken,
|
|
79
79
|
fetch_unpriceable_priced_tokens,
|
|
80
80
|
)
|
|
81
|
-
from ipor_fusion.types import
|
|
81
|
+
from ipor_fusion.types import (
|
|
82
|
+
ChainId,
|
|
83
|
+
MarketId,
|
|
84
|
+
MorphoBlueMarketId,
|
|
85
|
+
parse_morpho_market_id,
|
|
86
|
+
)
|
|
82
87
|
|
|
83
88
|
T = TypeVar("T")
|
|
84
89
|
|
|
@@ -484,9 +489,7 @@ def _collect_morpho_substrates(
|
|
|
484
489
|
for mid, subs in market_substrates.items():
|
|
485
490
|
if mid not in MORPHO_MARKET_IDS:
|
|
486
491
|
continue
|
|
487
|
-
morpho_ids = [
|
|
488
|
-
MorphoBlueMarketId(sub.hex()) for sub in subs if len(sub.hex()) == 64
|
|
489
|
-
]
|
|
492
|
+
morpho_ids = [parse_morpho_market_id(sub) for sub in subs if len(sub) == 32]
|
|
490
493
|
if morpho_ids:
|
|
491
494
|
result[mid] = morpho_ids
|
|
492
495
|
return result
|
|
@@ -196,7 +196,9 @@ class TestMorphoBlueCommand:
|
|
|
196
196
|
|
|
197
197
|
assert result.exit_code != 0
|
|
198
198
|
assert isinstance(result.exception, MorphoMarketNotFoundError)
|
|
199
|
-
assert f"market {MARKET_ID} does not exist on chain 1" in str(
|
|
199
|
+
assert f"market 0x{MARKET_ID} does not exist on chain 1" in str(
|
|
200
|
+
result.exception
|
|
201
|
+
)
|
|
200
202
|
mock_fetch.assert_not_called()
|
|
201
203
|
|
|
202
204
|
def test_no_api_skips_vault_section(
|
|
@@ -19,6 +19,7 @@ from ipor_fusion import (
|
|
|
19
19
|
fetch_vault_data,
|
|
20
20
|
format_market_label,
|
|
21
21
|
market_name,
|
|
22
|
+
parse_morpho_market_id,
|
|
22
23
|
validate_vault,
|
|
23
24
|
)
|
|
24
25
|
from ipor_fusion.chains import ensure_supported_chain
|
|
@@ -31,7 +32,7 @@ from ipor_fusion.crosschain.contracts import (
|
|
|
31
32
|
CrosschainFactory,
|
|
32
33
|
)
|
|
33
34
|
from ipor_fusion.explorer import get_contract_name
|
|
34
|
-
from ipor_fusion.morpho_api import fetch_vault
|
|
35
|
+
from ipor_fusion.morpho_api import fetch_market, fetch_vault
|
|
35
36
|
from ipor_fusion.readers.morpho import morpho_blue_address
|
|
36
37
|
from ipor_fusion.readers.unpriceable import fetch_unpriceable_priced_tokens
|
|
37
38
|
from ipor_fusion.types import (
|
|
@@ -74,6 +75,7 @@ def lookups() -> None:
|
|
|
74
75
|
get_contract_name(ETHEREUM, VAULT)
|
|
75
76
|
morpho_blue_address(ETHEREUM)
|
|
76
77
|
fetch_vault(VAULT, ETHEREUM)
|
|
78
|
+
fetch_market(parse_morpho_market_id("0x" + "ab" * 32), ETHEREUM)
|
|
77
79
|
|
|
78
80
|
|
|
79
81
|
def crosschain(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/advanced_euler_v2_credit_market_base.py
RENAMED
|
File without changes
|
{ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/advanced_euler_v2_looping_arbitrum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/examples/external_state_margin_leg_base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/oracle_mapping_view.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/cli/vault_markets_view.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev30 → ipor_fusion-4.0.0.dev32}/src/ipor_fusion/core/external_state_executor.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|