ipor-fusion 4.0.0.dev35__tar.gz → 4.0.0.dev37__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.dev35 → ipor_fusion-4.0.0.dev37}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/config_store.py +13 -2
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/market_cmd.py +6 -6
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/vault_cmd.py +1 -1
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/mcp/models.py +1 -1
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/mcp/server.py +5 -1
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/morpho_api.py +65 -43
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/validation.py +3 -3
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/vault_data.py +1 -1
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_mcp_models.py +19 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_mcp_server.py +14 -2
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/AGENTS.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/README.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/crosschain/base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/crosschain/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/crosschain/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/uv.lock +0 -0
|
@@ -6,7 +6,9 @@ from pathlib import Path
|
|
|
6
6
|
from urllib.parse import urlsplit
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
|
-
from
|
|
9
|
+
from eth_typing import ChecksumAddress
|
|
10
|
+
from pydantic import BaseModel, Field, ValidationError, field_validator, model_validator
|
|
11
|
+
from web3 import Web3
|
|
10
12
|
|
|
11
13
|
from ipor_fusion.types import ChainId
|
|
12
14
|
|
|
@@ -22,10 +24,19 @@ CONFIG_VERSION = 1
|
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
class VaultEntry(BaseModel):
|
|
25
|
-
address:
|
|
27
|
+
address: ChecksumAddress
|
|
26
28
|
label: str
|
|
27
29
|
chain_id: ChainId
|
|
28
30
|
|
|
31
|
+
@field_validator("address", mode="before")
|
|
32
|
+
@classmethod
|
|
33
|
+
def _checksum(cls, value: object) -> object:
|
|
34
|
+
# Configs written before 4.0 may hold any spelling; a value that is not
|
|
35
|
+
# an address is left for the commands to report, not for every load to fail.
|
|
36
|
+
if isinstance(value, str) and Web3.is_address(value):
|
|
37
|
+
return Web3.to_checksum_address(value)
|
|
38
|
+
return value
|
|
39
|
+
|
|
29
40
|
|
|
30
41
|
class FusionConfig(BaseModel):
|
|
31
42
|
providers: dict[str, str] = Field(default_factory=dict)
|
|
@@ -389,12 +389,12 @@ def _print_vault_v2(
|
|
|
389
389
|
click.echo("")
|
|
390
390
|
click.echo("Roles:")
|
|
391
391
|
click.echo(f" Owner: {vault.owner}")
|
|
392
|
-
click.echo(f" Curator: {vault.curator}")
|
|
392
|
+
click.echo(f" Curator: {vault.curator or ''}")
|
|
393
393
|
click.echo(
|
|
394
|
-
f" Performance fee: {vault.performance_fee * 100:.2f}% → {vault.performance_fee_recipient}"
|
|
394
|
+
f" Performance fee: {vault.performance_fee * 100:.2f}% → {vault.performance_fee_recipient or ''}"
|
|
395
395
|
)
|
|
396
396
|
click.echo(
|
|
397
|
-
f" Management fee: {vault.management_fee * 100:.2f}% → {vault.management_fee_recipient}"
|
|
397
|
+
f" Management fee: {vault.management_fee * 100:.2f}% → {vault.management_fee_recipient or ''}"
|
|
398
398
|
)
|
|
399
399
|
click.echo(f" Allocators ({len(vault.allocators)}):")
|
|
400
400
|
for addr in vault.allocators or ["(none)"]:
|
|
@@ -515,13 +515,13 @@ def _print_vault_v1(
|
|
|
515
515
|
f"({_format_amount(vault.total_assets, vault.asset_decimals)} total)"
|
|
516
516
|
)
|
|
517
517
|
click.echo(
|
|
518
|
-
f" Performance fee: {vault.fee_wad / WAD * 100:.2f}% → {vault.fee_recipient}"
|
|
518
|
+
f" Performance fee: {vault.fee_wad / WAD * 100:.2f}% → {vault.fee_recipient or ''}"
|
|
519
519
|
)
|
|
520
520
|
click.echo("")
|
|
521
521
|
click.echo("Roles:")
|
|
522
522
|
click.echo(f" Owner: {vault.owner}")
|
|
523
|
-
click.echo(f" Curator: {vault.curator}")
|
|
524
|
-
click.echo(f" Guardian: {vault.guardian}")
|
|
523
|
+
click.echo(f" Curator: {vault.curator or ''}")
|
|
524
|
+
click.echo(f" Guardian: {vault.guardian or ''}")
|
|
525
525
|
click.echo(f" Allocators ({len(vault.allocators)}):")
|
|
526
526
|
for addr in vault.allocators or ["(none)"]:
|
|
527
527
|
tag = (
|
|
@@ -95,7 +95,7 @@ def vault() -> None:
|
|
|
95
95
|
default=None,
|
|
96
96
|
help="Chain ID or name (auto-detected when only one provider is configured).",
|
|
97
97
|
)
|
|
98
|
-
def add(address:
|
|
98
|
+
def add(address: ChecksumAddress, label: str | None, chain_id: ChainId | None) -> None:
|
|
99
99
|
"""Save a vault to the config."""
|
|
100
100
|
cfg = load_config()
|
|
101
101
|
|
|
@@ -464,7 +464,11 @@ def vault_add(
|
|
|
464
464
|
save_config(cfg)
|
|
465
465
|
return ActionResult(message=f"Vault {label} ({address}) updated.")
|
|
466
466
|
|
|
467
|
-
cfg.vaults.append(
|
|
467
|
+
cfg.vaults.append(
|
|
468
|
+
VaultEntry(
|
|
469
|
+
address=Web3.to_checksum_address(address), label=label, chain_id=chain_id
|
|
470
|
+
)
|
|
471
|
+
)
|
|
468
472
|
save_config(cfg)
|
|
469
473
|
return ActionResult(message=f"Vault {label} ({address}) added.")
|
|
470
474
|
|
|
@@ -14,6 +14,7 @@ from urllib.error import URLError
|
|
|
14
14
|
from urllib.request import Request, urlopen
|
|
15
15
|
|
|
16
16
|
from eth_abi import decode, encode
|
|
17
|
+
from eth_typing import ChecksumAddress
|
|
17
18
|
from eth_utils import keccak
|
|
18
19
|
from web3 import Web3
|
|
19
20
|
|
|
@@ -97,7 +98,7 @@ class VaultFlowCap:
|
|
|
97
98
|
class VaultAllocation:
|
|
98
99
|
"""A MetaMorpho vault's exposure to a single Morpho Blue market."""
|
|
99
100
|
|
|
100
|
-
vault_address:
|
|
101
|
+
vault_address: ChecksumAddress
|
|
101
102
|
vault_name: str
|
|
102
103
|
vault_symbol: str
|
|
103
104
|
asset_symbol: str
|
|
@@ -115,10 +116,10 @@ class MorphoApiMarket:
|
|
|
115
116
|
|
|
116
117
|
market_id: MorphoBlueMarketId
|
|
117
118
|
lltv: int
|
|
118
|
-
loan_token:
|
|
119
|
+
loan_token: ChecksumAddress
|
|
119
120
|
loan_symbol: str
|
|
120
121
|
loan_decimals: int
|
|
121
|
-
collateral_token:
|
|
122
|
+
collateral_token: ChecksumAddress
|
|
122
123
|
collateral_symbol: str
|
|
123
124
|
collateral_decimals: int
|
|
124
125
|
oracle: str
|
|
@@ -182,10 +183,10 @@ def _parse_market(raw: dict) -> MorphoApiMarket:
|
|
|
182
183
|
return MorphoApiMarket(
|
|
183
184
|
market_id=_api_market_id(raw.get("marketId")),
|
|
184
185
|
lltv=int(raw["lltv"]),
|
|
185
|
-
loan_token=raw["loanAsset"]["address"],
|
|
186
|
+
loan_token=_api_address(raw["loanAsset"]["address"]),
|
|
186
187
|
loan_symbol=raw["loanAsset"]["symbol"],
|
|
187
188
|
loan_decimals=int(raw["loanAsset"]["decimals"]),
|
|
188
|
-
collateral_token=raw["collateralAsset"]["address"],
|
|
189
|
+
collateral_token=_api_address(raw["collateralAsset"]["address"]),
|
|
189
190
|
collateral_symbol=raw["collateralAsset"]["symbol"],
|
|
190
191
|
collateral_decimals=int(raw["collateralAsset"]["decimals"]),
|
|
191
192
|
oracle=raw["oracle"]["address"],
|
|
@@ -281,8 +282,8 @@ class VaultV2Cap:
|
|
|
281
282
|
relative_cap_wad: int
|
|
282
283
|
allocation: int
|
|
283
284
|
market_id: MorphoBlueMarketId | None
|
|
284
|
-
loan_token:
|
|
285
|
-
collateral_token:
|
|
285
|
+
loan_token: ChecksumAddress | None
|
|
286
|
+
collateral_token: ChecksumAddress | None
|
|
286
287
|
oracle: str | None
|
|
287
288
|
irm: str | None
|
|
288
289
|
lltv: int | None
|
|
@@ -297,20 +298,22 @@ class VaultV2Cap:
|
|
|
297
298
|
class VaultV2Adapter:
|
|
298
299
|
"""An adapter contract attached to a Vault V2 (e.g. Morpho adapter)."""
|
|
299
300
|
|
|
300
|
-
address:
|
|
301
|
+
address: ChecksumAddress
|
|
301
302
|
adapter_type: str
|
|
302
303
|
assets: int
|
|
303
|
-
inner_vault:
|
|
304
|
+
inner_vault: (
|
|
305
|
+
ChecksumAddress | None
|
|
306
|
+
) # for MorphoVaultV2Adapter: the underlying market vault
|
|
304
307
|
|
|
305
308
|
|
|
306
309
|
@dataclass(slots=True)
|
|
307
310
|
class VaultV2Info:
|
|
308
311
|
"""Snapshot of a Morpho Vault V2."""
|
|
309
312
|
|
|
310
|
-
address:
|
|
313
|
+
address: ChecksumAddress
|
|
311
314
|
name: str
|
|
312
315
|
symbol: str
|
|
313
|
-
asset_address:
|
|
316
|
+
asset_address: ChecksumAddress
|
|
314
317
|
asset_symbol: str
|
|
315
318
|
asset_decimals: int
|
|
316
319
|
total_assets: int
|
|
@@ -319,13 +322,13 @@ class VaultV2Info:
|
|
|
319
322
|
share_price: float
|
|
320
323
|
max_apy: float
|
|
321
324
|
performance_fee: float
|
|
322
|
-
performance_fee_recipient:
|
|
325
|
+
performance_fee_recipient: ChecksumAddress | None
|
|
323
326
|
management_fee: float
|
|
324
|
-
management_fee_recipient:
|
|
325
|
-
owner:
|
|
326
|
-
curator:
|
|
327
|
-
allocators: list[
|
|
328
|
-
sentinels: list[
|
|
327
|
+
management_fee_recipient: ChecksumAddress | None
|
|
328
|
+
owner: ChecksumAddress
|
|
329
|
+
curator: ChecksumAddress | None
|
|
330
|
+
allocators: list[ChecksumAddress]
|
|
331
|
+
sentinels: list[ChecksumAddress]
|
|
329
332
|
liquidity_adapter: VaultV2Adapter | None
|
|
330
333
|
adapters: list[VaultV2Adapter]
|
|
331
334
|
caps: list[VaultV2Cap] = field(default_factory=list)
|
|
@@ -355,19 +358,19 @@ class VaultV1MarketAllocation:
|
|
|
355
358
|
class VaultV1Info:
|
|
356
359
|
"""Snapshot of a MetaMorpho V1 vault."""
|
|
357
360
|
|
|
358
|
-
address:
|
|
361
|
+
address: ChecksumAddress
|
|
359
362
|
name: str
|
|
360
363
|
symbol: str
|
|
361
|
-
asset_address:
|
|
364
|
+
asset_address: ChecksumAddress
|
|
362
365
|
asset_symbol: str
|
|
363
366
|
asset_decimals: int
|
|
364
367
|
total_assets: int
|
|
365
368
|
fee_wad: int
|
|
366
|
-
owner:
|
|
367
|
-
curator:
|
|
368
|
-
guardian:
|
|
369
|
-
fee_recipient:
|
|
370
|
-
allocators: list[
|
|
369
|
+
owner: ChecksumAddress
|
|
370
|
+
curator: ChecksumAddress | None
|
|
371
|
+
guardian: ChecksumAddress | None
|
|
372
|
+
fee_recipient: ChecksumAddress | None
|
|
373
|
+
allocators: list[ChecksumAddress]
|
|
371
374
|
allocations: list[VaultV1MarketAllocation]
|
|
372
375
|
public_allocator: VaultFlowCap | None # vault-level (no flowCap filtering)
|
|
373
376
|
public_allocator_flow_caps: dict[str, tuple[int, int]] # marketId -> (maxIn,maxOut)
|
|
@@ -431,10 +434,10 @@ def _parse_vault_v2(raw: dict) -> VaultV2Info:
|
|
|
431
434
|
]
|
|
432
435
|
caps = [_parse_v2_cap(c) for c in (raw.get("caps") or {}).get("items", []) if c]
|
|
433
436
|
return VaultV2Info(
|
|
434
|
-
address=raw
|
|
437
|
+
address=_api_address(raw.get("address")),
|
|
435
438
|
name=raw.get("name") or "",
|
|
436
439
|
symbol=raw.get("symbol") or "",
|
|
437
|
-
asset_address=asset.get("address")
|
|
440
|
+
asset_address=_api_address(asset.get("address")),
|
|
438
441
|
asset_symbol=asset.get("symbol") or "",
|
|
439
442
|
asset_decimals=int(asset.get("decimals") or 0),
|
|
440
443
|
total_assets=int(raw.get("totalAssets") or 0),
|
|
@@ -443,18 +446,22 @@ def _parse_vault_v2(raw: dict) -> VaultV2Info:
|
|
|
443
446
|
share_price=float(raw.get("sharePrice") or 0.0),
|
|
444
447
|
max_apy=float(raw.get("maxApy") or 0.0),
|
|
445
448
|
performance_fee=float(raw.get("performanceFee") or 0.0),
|
|
446
|
-
performance_fee_recipient=
|
|
449
|
+
performance_fee_recipient=_api_optional_address(
|
|
450
|
+
raw.get("performanceFeeRecipient")
|
|
451
|
+
),
|
|
447
452
|
management_fee=float(raw.get("managementFee") or 0.0),
|
|
448
|
-
management_fee_recipient=
|
|
449
|
-
|
|
450
|
-
|
|
453
|
+
management_fee_recipient=_api_optional_address(
|
|
454
|
+
raw.get("managementFeeRecipient")
|
|
455
|
+
),
|
|
456
|
+
owner=_api_address((raw.get("owner") or {}).get("address")),
|
|
457
|
+
curator=_api_optional_address((raw.get("curator") or {}).get("address")),
|
|
451
458
|
allocators=[
|
|
452
|
-
a["allocator"]["address"]
|
|
459
|
+
_api_address(a["allocator"]["address"])
|
|
453
460
|
for a in raw.get("allocators") or []
|
|
454
461
|
if (a.get("allocator") or {}).get("address")
|
|
455
462
|
],
|
|
456
463
|
sentinels=[
|
|
457
|
-
s["sentinel"]["address"]
|
|
464
|
+
_api_address(s["sentinel"]["address"])
|
|
458
465
|
for s in raw.get("sentinels") or []
|
|
459
466
|
if (s.get("sentinel") or {}).get("address")
|
|
460
467
|
],
|
|
@@ -466,10 +473,10 @@ def _parse_vault_v2(raw: dict) -> VaultV2Info:
|
|
|
466
473
|
|
|
467
474
|
def _parse_v2_adapter(raw: dict) -> VaultV2Adapter:
|
|
468
475
|
return VaultV2Adapter(
|
|
469
|
-
address=raw.get("address")
|
|
476
|
+
address=_api_address(raw.get("address")),
|
|
470
477
|
adapter_type=raw.get("type") or raw.get("__typename") or "",
|
|
471
478
|
assets=int(raw.get("assets") or 0),
|
|
472
|
-
inner_vault=(raw.get("metaMorpho") or {}).get("address"),
|
|
479
|
+
inner_vault=_api_optional_address((raw.get("metaMorpho") or {}).get("address")),
|
|
473
480
|
)
|
|
474
481
|
|
|
475
482
|
|
|
@@ -500,7 +507,10 @@ def _parse_v2_cap(raw: dict) -> VaultV2Cap:
|
|
|
500
507
|
|
|
501
508
|
def _decode_market_v1_id_data(
|
|
502
509
|
id_data: str,
|
|
503
|
-
) ->
|
|
510
|
+
) -> (
|
|
511
|
+
tuple[ChecksumAddress, ChecksumAddress, ChecksumAddress, ChecksumAddress, int]
|
|
512
|
+
| None
|
|
513
|
+
):
|
|
504
514
|
"""Decode a Vault V2 `MarketV1`-type cap idData into MarketParams.
|
|
505
515
|
|
|
506
516
|
Vault V2 encodes the cap idData as `abi.encode(string idType, address adapter,
|
|
@@ -548,6 +558,16 @@ def _decode_market_v1_id_data(
|
|
|
548
558
|
)
|
|
549
559
|
|
|
550
560
|
|
|
561
|
+
def _api_address(value: object) -> ChecksumAddress:
|
|
562
|
+
if not isinstance(value, str) or not Web3.is_address(value):
|
|
563
|
+
raise MorphoApiError(f"Morpho API returned an invalid address: {value!r}")
|
|
564
|
+
return Web3.to_checksum_address(value)
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
def _api_optional_address(value: object) -> ChecksumAddress | None:
|
|
568
|
+
return None if value is None or value == "" else _api_address(value)
|
|
569
|
+
|
|
570
|
+
|
|
551
571
|
def _api_market_id(value: object) -> MorphoBlueMarketId:
|
|
552
572
|
try:
|
|
553
573
|
return parse_morpho_market_id(str(value or ""))
|
|
@@ -612,20 +632,22 @@ def _parse_vault_v1(raw: dict) -> VaultV1Info:
|
|
|
612
632
|
flow_caps[mid] = (int(fc.get("maxIn") or 0), int(fc.get("maxOut") or 0))
|
|
613
633
|
|
|
614
634
|
return VaultV1Info(
|
|
615
|
-
address=raw
|
|
635
|
+
address=_api_address(raw.get("address")),
|
|
616
636
|
name=raw.get("name") or "",
|
|
617
637
|
symbol=raw.get("symbol") or "",
|
|
618
|
-
asset_address=asset.get("address")
|
|
638
|
+
asset_address=_api_address(asset.get("address")),
|
|
619
639
|
asset_symbol=asset.get("symbol") or "",
|
|
620
640
|
asset_decimals=int(asset.get("decimals") or 0),
|
|
621
641
|
total_assets=int(state.get("totalAssets") or 0),
|
|
622
642
|
fee_wad=int(state.get("fee") or 0),
|
|
623
|
-
owner=state.get("owner")
|
|
624
|
-
curator=state.get("curator")
|
|
625
|
-
guardian=state.get("guardian")
|
|
626
|
-
fee_recipient=state.get("feeRecipient")
|
|
643
|
+
owner=_api_address(state.get("owner")),
|
|
644
|
+
curator=_api_optional_address(state.get("curator")),
|
|
645
|
+
guardian=_api_optional_address(state.get("guardian")),
|
|
646
|
+
fee_recipient=_api_optional_address(state.get("feeRecipient")),
|
|
627
647
|
allocators=[
|
|
628
|
-
a["address"]
|
|
648
|
+
_api_address(a["address"])
|
|
649
|
+
for a in raw.get("allocators") or []
|
|
650
|
+
if a.get("address")
|
|
629
651
|
],
|
|
630
652
|
allocations=allocations,
|
|
631
653
|
public_allocator=flow_cap_summary,
|
|
@@ -667,7 +689,7 @@ def _parse_vault(raw: dict, market_id: MorphoBlueMarketId) -> VaultAllocation:
|
|
|
667
689
|
a["address"] for a in (raw.get("allocators") or []) if a.get("address")
|
|
668
690
|
]
|
|
669
691
|
return VaultAllocation(
|
|
670
|
-
vault_address=raw["address"],
|
|
692
|
+
vault_address=_api_address(raw["address"]),
|
|
671
693
|
vault_name=raw.get("name") or "",
|
|
672
694
|
vault_symbol=raw.get("symbol") or "",
|
|
673
695
|
asset_symbol=asset.get("symbol") or "",
|
|
@@ -98,7 +98,7 @@ class VaultState(Protocol):
|
|
|
98
98
|
@property
|
|
99
99
|
def block_timestamp(self) -> int: ...
|
|
100
100
|
@property
|
|
101
|
-
def asset(self) ->
|
|
101
|
+
def asset(self) -> ChecksumAddress: ...
|
|
102
102
|
@property
|
|
103
103
|
def asset_symbol(self) -> str: ...
|
|
104
104
|
@property
|
|
@@ -219,11 +219,11 @@ class VaultValidation:
|
|
|
219
219
|
found. Raw amounts are in the underlying ``asset``'s decimals.
|
|
220
220
|
"""
|
|
221
221
|
|
|
222
|
-
vault:
|
|
222
|
+
vault: ChecksumAddress
|
|
223
223
|
chain_id: ChainId
|
|
224
224
|
block_number: int
|
|
225
225
|
block_timestamp: int
|
|
226
|
-
asset:
|
|
226
|
+
asset: ChecksumAddress
|
|
227
227
|
asset_symbol: str
|
|
228
228
|
asset_decimals: int
|
|
229
229
|
asset_price_usd: float | None
|
|
@@ -666,6 +666,25 @@ class TestSimpleResponseContracts:
|
|
|
666
666
|
assert result.version == "v2"
|
|
667
667
|
assert result.fee_wad is None # v1-only stays unset
|
|
668
668
|
|
|
669
|
+
def test_meta_morpho_without_a_curator_validates(self):
|
|
670
|
+
d = {
|
|
671
|
+
"version": "v1",
|
|
672
|
+
"chain_id": 1,
|
|
673
|
+
"address": "0xVAULT",
|
|
674
|
+
"name": "v",
|
|
675
|
+
"symbol": "v",
|
|
676
|
+
"asset": {"address": "0xL", "symbol": "USDC", "decimals": 6},
|
|
677
|
+
"total_assets": "1000",
|
|
678
|
+
"owner": "0xOWNER",
|
|
679
|
+
"curator": None,
|
|
680
|
+
"guardian": None,
|
|
681
|
+
"fee_recipient": None,
|
|
682
|
+
"allocators": [],
|
|
683
|
+
}
|
|
684
|
+
result = MetaMorphoVaultResponse.model_validate(d)
|
|
685
|
+
assert result.curator is None
|
|
686
|
+
assert result.guardian is None
|
|
687
|
+
|
|
669
688
|
def test_meta_morpho_v1_validates(self):
|
|
670
689
|
d = {
|
|
671
690
|
"version": "v1",
|
|
@@ -331,10 +331,22 @@ class TestVaultAdd:
|
|
|
331
331
|
return_value=_config_with_provider(),
|
|
332
332
|
)
|
|
333
333
|
def test_add_with_label_and_chain(self, mock_load, mock_save):
|
|
334
|
-
|
|
334
|
+
lowercase = "0x43ee0243ea8cf02f7087d8b16c8d2007cc9c7ca2"
|
|
335
|
+
result = vault_add(address=lowercase, label="New Vault", chain_id=1)
|
|
335
336
|
assert "added" in result.message.lower()
|
|
336
337
|
saved_cfg = mock_save.call_args[0][0]
|
|
337
|
-
assert any(
|
|
338
|
+
assert any(
|
|
339
|
+
v.address == Web3.to_checksum_address(lowercase) for v in saved_cfg.vaults
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
@patch("ipor_fusion.mcp.server.save_config")
|
|
343
|
+
@patch(
|
|
344
|
+
"ipor_fusion.mcp.server.load_config",
|
|
345
|
+
return_value=_config_with_provider(),
|
|
346
|
+
)
|
|
347
|
+
def test_add_rejects_a_non_address(self, mock_load, mock_save):
|
|
348
|
+
with pytest.raises(ValueError):
|
|
349
|
+
vault_add(address="0xDEF", label="New Vault", chain_id=1)
|
|
338
350
|
|
|
339
351
|
@patch("ipor_fusion.mcp.server.save_config")
|
|
340
352
|
@patch(
|
|
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
|
|
File without changes
|
{ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/advanced_euler_v2_credit_market_base.py
RENAMED
|
File without changes
|
{ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/examples/advanced_euler_v2_looping_arbitrum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/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.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/cli/oracle_mapping_view.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/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.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/external_state_executor.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.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/core/withdraw_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev35 → ipor_fusion-4.0.0.dev37}/src/ipor_fusion/crosschain/ccip/__init__.py
RENAMED
|
File without changes
|