ipor-fusion 4.0.0.dev240__tar.gz → 4.0.0.dev249__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.dev240 → ipor_fusion-4.0.0.dev249}/AGENTS.md +39 -20
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/MIGRATION_4.md +45 -27
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/PKG-INFO +15 -8
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/README.md +14 -7
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/market_cmd.py +6 -5
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/mcp/server.py +16 -9
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_mcp_server.py +76 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/simulation_result.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/hypercore/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_data.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_event_args.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_fake_rpc.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_golden.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_live.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_oracle_mapping_fake.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/simulate_v1_request.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/fetched.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/full.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/full.txt +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_market_golden.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_mcp_parity.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_oracle_mapping_golden.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_public_api.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulation_errors.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_simulation_observation.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_vault_data_block.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_vault_info_fetched_golden.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_vault_reconciliation_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/tests/typed_client/rejected.py +0 -0
- {ipor_fusion-4.0.0.dev240 → ipor_fusion-4.0.0.dev249}/uv.lock +0 -0
|
@@ -28,7 +28,7 @@ uv run ruff format ./ # format (CI runs
|
|
|
28
28
|
uv run ruff check ./ # lint: bandit S, C901 max-complexity 10, PLR limits
|
|
29
29
|
uv run pyright # types, basic mode, src + tests + examples + scripts
|
|
30
30
|
uv run pytest # all tests + coverage gate (fail_under = 98, mcp/ included)
|
|
31
|
-
uv run pytest -m "cli or mcp" --no-cov #
|
|
31
|
+
uv run pytest -m "cli or mcp" --no-cov # CLI/MCP subset (the full suite is mostly offline too)
|
|
32
32
|
uv run pytest --run-readiness -m readiness --no-cov -rA # opt-in live Ethereum-hub POC checks
|
|
33
33
|
uv run python scripts/crosschain_readiness.py --output /tmp/crosschain-readiness.json # live Arbitrum/HyperEVM report
|
|
34
34
|
uv run pytest tests/test_fuse_encoding.py -k aave --no-cov # single file / test
|
|
@@ -59,9 +59,9 @@ everything else is `sdk`). Most `sdk` tests are offline too: the suite with no
|
|
|
59
59
|
provider set still clears the coverage gate.
|
|
60
60
|
Integration tests (`test_simulate_*`, `test_vault_info_onchain_*`) run against
|
|
61
61
|
live RPCs via `eth_simulateV1`, no Docker or Anvil (`ANVIL_WALLET` is just a
|
|
62
|
-
named address constant).
|
|
63
|
-
`BASE_PROVIDER_URL`
|
|
64
|
-
python-dotenv)
|
|
62
|
+
named address constant). Each skips unless the provider it needs
|
|
63
|
+
(`ETHEREUM_PROVIDER_URL`, `BASE_PROVIDER_URL` or `ARBITRUM_PROVIDER_URL`; `.env` is
|
|
64
|
+
loaded via python-dotenv) is set and supports `eth_simulateV1`. Every such gate goes
|
|
65
65
|
through `tests/_live.py` (`provider_url`, `archive_context`, `unavailable`): it
|
|
66
66
|
skips locally and fails when the source is named in `IPOR_FUSION_REQUIRE_LIVE`
|
|
67
67
|
(comma-separated env var names, `GITHUB` for the Solidity mirrors). CI
|
|
@@ -84,9 +84,11 @@ executors from the creation code they store; `source` builds a factory pair from
|
|
|
84
84
|
that revision (the fuses are compiled from it); a checkout without `node_modules` also
|
|
85
85
|
needs `IPOR_FUSION_FOUNDRY_REMAPPINGS` for OpenZeppelin. `test_crosschain_ccip_events.py`
|
|
86
86
|
mirrors the CCIP event registry from a checkout at its own `CONTRACTS_REVISION`.
|
|
87
|
-
`test_solidity_compiler.py`
|
|
88
|
-
|
|
89
|
-
external prerequisites are unavailable.
|
|
87
|
+
`test_solidity_compiler.py` unit-tests that compiler helper (`tests/_foundry.py`)
|
|
88
|
+
offline, with `forge` and `git` mocked. The checkout-based tests above skip when their
|
|
89
|
+
external prerequisites are unavailable. `test_hypercore_live.py`,
|
|
90
|
+
`test_hypercore_deployment.py` and `test_hypercore_simulation.py` need
|
|
91
|
+
`HYPEREVM_PROVIDER_URL` as well.
|
|
90
92
|
`test_simulate_crosschain_lifecycle.py` drives the mainnet POC deployment from
|
|
91
93
|
Ethereum to every spoke on every transport through `CrosschainLane` and
|
|
92
94
|
`CrosschainSimulator`; the fixtures (`Chain`, `Deployment`, `Spoke`, pinned
|
|
@@ -110,8 +112,9 @@ the deployed runtimes, and `tests/_hypercore_model.py` answers those addresses t
|
|
|
110
112
|
tests prove EVM validation under supplied Core state. `test_hypercore_simulation.py`
|
|
111
113
|
runs one vault cycle; `test_simulate_crosschain_hypercore.py` runs the composed flow
|
|
112
114
|
(v3 canary hub → CCIP → the market-55 vault → a trade → recall → claim) and holds every
|
|
113
|
-
CCIP delivery to its route gas limit. Both skip without the source directory
|
|
114
|
-
|
|
115
|
+
CCIP delivery to its route gas limit. Both skip without the source directory;
|
|
116
|
+
`test_hypercore_simulation.py` also needs `HYPEREVM_PROVIDER_URL`, the composed flow
|
|
117
|
+
`ARBITRUM_PROVIDER_URL` as well.
|
|
115
118
|
`test_crosschain_readiness.py` checks the Ethereum-hub POC's live bridge and IPOR
|
|
116
119
|
preconditions. Its `readiness` marker requires `--run-readiness`: ordinary runs
|
|
117
120
|
exclude it even with `-m sdk`. Known HyperEVM gaps are non-strict xfails restricted
|
|
@@ -243,8 +246,10 @@ the lifecycle matrix follows that.
|
|
|
243
246
|
snapshots), `vault_positions.py` (Morpho/Aave position breakdowns and their token
|
|
244
247
|
prices) and `vault_erc20.py` (the ERC20_VAULT_BALANCE holdings);
|
|
245
248
|
`vault_info.py` — `build_vault_info_json(data)`, the `fusion vault info --json`
|
|
246
|
-
document rendered from the snapshot
|
|
247
|
-
|
|
249
|
+
document rendered from the snapshot, plus three inputs that are not chain state at
|
|
250
|
+
its block: contract names through the injected `resolve_name` (Etherscan I/O on a
|
|
251
|
+
pool), the deployment fields the caller writes into the snapshot from
|
|
252
|
+
`fetch_deployment_info`, and `age_days` from the wall clock; typed block by block (`VaultInfoJson` and its nested
|
|
248
253
|
TypedDicts), and `health_check_lists`; `explorer.py` Etherscan V2 (single endpoint, needs API key);
|
|
249
254
|
`cache.py` the `ContractCache` protocol (`get`/`put` of immutable facts keyed
|
|
250
255
|
`CacheKey(chain_id, address, field)`), `FileContractCache` (one JSON file, atomic
|
|
@@ -284,13 +289,16 @@ the lifecycle matrix follows that.
|
|
|
284
289
|
uniswap_v3, universal); `events.py` (`extract_events`, `abi_value` and the raw-log
|
|
285
290
|
event decoder both event families share), `external_state_event_decoding.py` and
|
|
286
291
|
`hypercore_event_decoding.py` (the ExternalState and HyperCore event specs, classes
|
|
287
|
-
and decoders; internal modules, the names are exported from
|
|
292
|
+
and decoders; internal modules, the ExternalState names are exported from
|
|
293
|
+
`ipor_fusion.fuses`, the HyperCore ones from `ipor_fusion.hypercore`), `hypercore.py`
|
|
294
|
+
(the HyperCore fuses, market 55);
|
|
288
295
|
`base.py` re-exports the `core/fuse.py` base and validators,
|
|
289
296
|
`FuseAction` and `ZERO_ADDRESS` (from `types`). A fuse is a value: equality and
|
|
290
297
|
hash cover its class and every attribute it stores
|
|
291
298
|
- `crosschain/` — crosschain Plasma Vaults (executor on the hub chain, dispatcher at
|
|
292
299
|
the same address on each spoke chain), split like the contracts: shared `messages`
|
|
293
|
-
(`Command`, `MsgType`, envelopes), `
|
|
300
|
+
(`Command`, `MsgType`, envelopes), `logs` (`log_bytes` and the raw-log field
|
|
301
|
+
helpers the decoders share), `contracts` (wrapper bases), `transport`
|
|
294
302
|
(`CrosschainTransport` seam), `lane` (`CrosschainLane`: one executor/dispatcher pair
|
|
295
303
|
driven without knowing its transport; it carries its transport's fuse classes and
|
|
296
304
|
the keeper's attestation helpers), `discovery` (`discover_deployment` reads the
|
|
@@ -304,6 +312,8 @@ the lifecycle matrix follows that.
|
|
|
304
312
|
`ccip/`, each with its wire codecs, executor/dispatcher/factory wrappers, transport
|
|
305
313
|
and lane; `ccip/chainlink` reads Chainlink's Router, OnRamp, TokenAdminRegistry and
|
|
306
314
|
token pool (`ccip_token_lane`: is there a lane, does the token travel on it);
|
|
315
|
+
`ccip/quote` (`quote_ccip_native_fee`: the exact native fee of a send, from a
|
|
316
|
+
simulation with the payer's balance at zero);
|
|
307
317
|
`ccip/events` decodes the executor/dispatcher/factory events by topic (one
|
|
308
318
|
registry, mirrored from the v3 source; the v2 pair emits a subset of it);
|
|
309
319
|
`ccip/chainlink` also wraps the 2.0 OffRamp, verifier resolver and committee verifier
|
|
@@ -314,19 +324,27 @@ the lifecycle matrix follows that.
|
|
|
314
324
|
mirroring `contracts/fuses/crosschain/`; they build on `core/fuse.py`, so the
|
|
315
325
|
dependency direction is `core` <- `crosschain` and `fuses/` holds no crosschain code
|
|
316
326
|
(neither package imports the other). Names mirror the Solidity contracts and
|
|
317
|
-
libraries. Adding a transport: a new subpackage, its encoders in `crosschain/fuses
|
|
318
|
-
|
|
327
|
+
libraries. Adding a transport: a new subpackage, its encoders in `crosschain/fuses/`,
|
|
328
|
+
one `LANES` entry and its probe in `discovery.detect_transport` (CCIP answers
|
|
329
|
+
`transportKind()`, Stargate a non-zero `STARGATE_POOL()`). Layering: the encoders import the wire codecs and wrappers;
|
|
319
330
|
lanes, discovery, transports and the simulator import the encoders.
|
|
320
331
|
`ipor_fusion.crosschain` exports the whole surface (encoders, lanes, discovery,
|
|
321
332
|
transports, simulator). A package `__init__` runs before its modules and the
|
|
322
333
|
encoders import `ccip.contracts` / `stargate.layerzero`, so `.ccip` and `.stargate`
|
|
323
|
-
export only their codecs and wrappers
|
|
334
|
+
export only what sits below the encoders: their codecs and wrappers, and for
|
|
335
|
+
`.ccip` also the Chainlink readers (`ccip_token_lane`), the fee quote
|
|
336
|
+
(`quote_ccip_native_fee`) and the indexer client (`fetch_verifier_result`,
|
|
337
|
+
`manual_execution`). `tests/test_crosschain_layering.py` pins this:
|
|
324
338
|
the SDK's module-level import graph, with the implicit package-`__init__` edges, is
|
|
325
339
|
acyclic, and the crosschain package has no function-level or `TYPE_CHECKING`
|
|
326
340
|
imports; never work around a cycle with a lazy import, move the module instead.
|
|
327
|
-
- `readers/` — read side: lending_health, oracle_mapping
|
|
328
|
-
|
|
329
|
-
|
|
341
|
+
- `readers/` — read side: lending_health, oracle_mapping (with oracle_mapping_nodes
|
|
342
|
+
and oracle_mapping_reader), position_manager, aave_v3, aave_v4, compound_v3, morpho,
|
|
343
|
+
ramses_v2, uniswap_v3, unpriceable (middleware-priced tokens of granted substrates
|
|
344
|
+
the oracle cannot price), hypercore and hypercore_outcome (HyperCore reads and
|
|
345
|
+
transfer outcomes)
|
|
346
|
+
- `hypercore/` — the preview HyperCore names re-exported from `fuses/hypercore*.py`
|
|
347
|
+
and `readers/hypercore*.py`; no code of its own
|
|
330
348
|
- `cli/` — `main.py` root group; `changelog_cmd.py`, `config_cmd.py`, `market_cmd.py`,
|
|
331
349
|
`vault_cmd.py` command orchestration over `vault_data` / `vault_info`; `options.py`
|
|
332
350
|
the shared `--chain-id` / address param types and chain/provider resolution;
|
|
@@ -387,7 +405,8 @@ or examples.
|
|
|
387
405
|
- Fuses (`fuses/`) are stateless encoders: a method returns an immutable
|
|
388
406
|
`FuseAction(fuse_address, calldata)` and touches no chain. `Fuse` builds it
|
|
389
407
|
via `self._action_raw(solidity_signature, values)`; the shared `_validate_*`
|
|
390
|
-
helpers raise before encoding
|
|
408
|
+
helpers raise before encoding (the HyperCore encoders add their own integer-width
|
|
409
|
+
checks, `_validate_uint` / `_validate_positive_uint` in `fuses/hypercore.py`). `PlasmaVault.execute([actions])` runs the
|
|
391
410
|
batch atomically.
|
|
392
411
|
- Pin reads, never mutate a shared context: `ctx.at_block(n)` is a copy whose
|
|
393
412
|
reads (and `get_logs` upper bound) default to block ``n``; `Call.call(ctx, block=n)`
|
|
@@ -20,8 +20,9 @@ the details, and each change is described once, in its section.
|
|
|
20
20
|
> checker cannot see the calls made through them;
|
|
21
21
|
> - run the reads against a provider, not only the test suite.
|
|
22
22
|
|
|
23
|
-
Work through these in order
|
|
24
|
-
|
|
23
|
+
Work through these in order. Removed imports fail first, at import; the rest is
|
|
24
|
+
the recommended order, roughly what fails next at run time (a positional option
|
|
25
|
+
such as `Web3Context.from_url(url, key)` can fail before any wrapper is built).
|
|
25
26
|
|
|
26
27
|
1. **Removed and renamed imports fail first, at import.** The preview features
|
|
27
28
|
left the top level: crosschain names import from `ipor_fusion.crosschain`,
|
|
@@ -47,8 +48,9 @@ before it is fixed.
|
|
|
47
48
|
raises `AttributeError`. See [Vault reads and validation](#vault-reads-and-validation).
|
|
48
49
|
5. **The vault read is one snapshot.** `fetch_vault_data(ctx, vault, *, block=None,
|
|
49
50
|
lending=True, metadata=True)` takes the vault address and the chain from `ctx`;
|
|
50
|
-
`validate_vault_state(state)` and `build_vault_info_json(data, *,
|
|
51
|
-
resolve_name=None)`
|
|
51
|
+
`validate_vault_state(state)` reads nothing, and `build_vault_info_json(data, *,
|
|
52
|
+
resolve_name=None)` reads no vault state (contract names come from
|
|
53
|
+
`resolve_name`, the deployment age from the wall clock). See [Vault reads and validation](#vault-reads-and-validation).
|
|
52
54
|
6. **Simulations return typed observations.** `sim.observe("label", call)` raises
|
|
53
55
|
`TypeError`: `read = sim.observe(call, label="label")` returns a
|
|
54
56
|
`SimulationObservation`, read as `read.value` after `run()`;
|
|
@@ -282,7 +284,8 @@ The vault read is one pinned snapshot, and the chain is always the context's:
|
|
|
282
284
|
`VaultState` also provides `vault`, `chain_id`, `market_balances`, `erc20` and the
|
|
283
285
|
queue's `shares_to_release_assets`.
|
|
284
286
|
- `build_vault_info_json(data, *, resolve_name=None)` renders from the snapshot and
|
|
285
|
-
reads
|
|
287
|
+
reads no vault state (`resolve_name`, which may look names up, and the deployment
|
|
288
|
+
age, computed from the wall clock, are its only other inputs); the chain and its label come from `data.chain_id`. Without
|
|
286
289
|
`resolve_name` it names no contract (see
|
|
287
290
|
[Contract cache and request limit](#contract-cache-and-request-limit)).
|
|
288
291
|
- `fetch_deployment_info(ctx, vault, *, api_key=None)` and
|
|
@@ -301,14 +304,16 @@ The vault read is one pinned snapshot, and the chain is always the context's:
|
|
|
301
304
|
|
|
302
305
|
**Public API.** 4.0 declares it: `ipor_fusion.__all__`, which now also exports the
|
|
303
306
|
names earlier reachable only by module path (`FusionFactory`, `FusionInstance`,
|
|
304
|
-
`fetch_market`, `resolve_token_symbol`, the
|
|
307
|
+
`fetch_market`, `resolve_token_symbol`, ...); the preview features are exported only
|
|
308
|
+
from their subpackages (see below). Import from
|
|
305
309
|
`ipor_fusion`: a module path outside the README's list (*Public API and stability*)
|
|
306
310
|
still works but is internal. Every project type a public signature or field uses is
|
|
307
311
|
exported too, among them `AaveV3PositionBreakdown`, `AaveV3ReserveTokens`,
|
|
308
|
-
`AccountRequest`, `StateOverrideProvider
|
|
312
|
+
`AccountRequest`, `StateOverrideProvider` and the validation
|
|
309
313
|
vocabulary `Severity`, `Verdict` and `Check`. Also new: `InFlightLimit` (see
|
|
310
|
-
[Contract cache and request limit](#contract-cache-and-request-limit)) and
|
|
311
|
-
`log_bytes`, the hex-or-bytes log field helper the
|
|
314
|
+
[Contract cache and request limit](#contract-cache-and-request-limit)), and in
|
|
315
|
+
`ipor_fusion.crosschain` `log_bytes`, the hex-or-bytes log field helper the
|
|
316
|
+
crosschain decoders use.
|
|
312
317
|
|
|
313
318
|
**Crosschain fuse encoders moved.** The crosschain market encoders moved from
|
|
314
319
|
`ipor_fusion.fuses.crosschain` into the crosschain package, and
|
|
@@ -391,9 +396,9 @@ the modules are internal.
|
|
|
391
396
|
- `MORPHO_BLUE_ADDRESS`: use `morpho_blue_address(chain_id)`. `BLOCK_EXPLORER_URLS`,
|
|
392
397
|
`MORPHO_BLUE_ADDRESSES`, `AAVE_V3_POOL` and `explorer.SUPPORTED_CHAINS` are
|
|
393
398
|
internal. Import `CHAIN_NAMES`, `CHAIN_NAME_TO_ID`, `SUPPORTED_CHAIN_IDS`,
|
|
394
|
-
`GET_LOGS_RANGE_HINTS`, `PUBLIC_ALLOCATOR_ADDRESSES
|
|
395
|
-
`
|
|
396
|
-
|
|
399
|
+
`GET_LOGS_RANGE_HINTS`, `PUBLIC_ALLOCATOR_ADDRESSES` and `HYPEREVM_CHAIN_ID` from
|
|
400
|
+
`ipor_fusion` (`HYPEREVM_CHAIN_ID` also from `ipor_fusion.readers`), and
|
|
401
|
+
`HYPERCORE_PENDING_READERS` and `HYPERCORE_MARKET` from `ipor_fusion.hypercore`.
|
|
397
402
|
- `read_erc20_holdings`: the holdings are `VaultData.erc20`.
|
|
398
403
|
- `ExternalStateExecutor.mark_nav` and `NavMark`: send `propose_balance` and
|
|
399
404
|
`confirm_balance` from separate custodians, then
|
|
@@ -626,7 +631,10 @@ typed client with pyright's `reportArgumentType`. Other fields keep their types
|
|
|
626
631
|
the SDK returns already carry their type and go back in unwrapped.
|
|
627
632
|
|
|
628
633
|
The SDK's own types are importable from `ipor_fusion` (and the public module
|
|
629
|
-
`ipor_fusion.types`),
|
|
634
|
+
`ipor_fusion.types`), except the preview features' ids, which come from their
|
|
635
|
+
subpackages: the crosschain ids (`CommandId`, ...) from `ipor_fusion.crosschain`, the
|
|
636
|
+
HyperCore ids (`HyperCoreAsset`, ...), `USDC_TOKEN_INDEX` and `hip3_action_asset`
|
|
637
|
+
from `ipor_fusion.hypercore`. Third-party
|
|
630
638
|
types are not re-exported: `ChecksumAddress` and `HexAddress` come from `eth_typing`,
|
|
631
639
|
and `BlockIdentifier`, `Timestamp` and `TxParams` from `web3.types`. The wrappers
|
|
632
640
|
label values; they do not validate byte widths or address spelling.
|
|
@@ -890,8 +898,10 @@ oracle node's `source_detail`, the Morpho `asset`, `adapters`, `caps`,
|
|
|
890
898
|
## Typed JSON documents
|
|
891
899
|
|
|
892
900
|
The JSON document builders return `TypedDict`s instead of `dict[str, Any]`; the
|
|
893
|
-
|
|
894
|
-
|
|
901
|
+
typing itself changes no document (keys, values, order); the documents' own 4.0
|
|
902
|
+
changes are listed under [Behavior changes](#behavior-changes) (the validation
|
|
903
|
+
document, reconciliation and lending-health fields, MCP null keys, addresses,
|
|
904
|
+
supply cap).
|
|
895
905
|
|
|
896
906
|
| Builder | Returns |
|
|
897
907
|
|---|---|
|
|
@@ -968,8 +978,9 @@ class. An event's args TypedDict is its class's `args` annotation:
|
|
|
968
978
|
`typing.get_type_hints(EXTERNAL_STATE_EVENT_CLASSES[name])["args"]`. Values carry
|
|
969
979
|
nominal types (`Amount`, `MarketId`, `FuseAddress`, `HyperCoreTokenIndex`,
|
|
970
980
|
`PayloadHash`, web3's `Timestamp`, ...), and `HyperCoreEvent.fuse` is a
|
|
971
|
-
`FuseAddress | None` on every event.
|
|
972
|
-
|
|
981
|
+
`FuseAddress | None` on every event. The ExternalState names are importable from
|
|
982
|
+
`ipor_fusion` and `ipor_fusion.fuses`; the HyperCore ones (preview) only from
|
|
983
|
+
`ipor_fusion.hypercore`.
|
|
973
984
|
|
|
974
985
|
The two families share one input contract. `decode_external_state_event(log)` and
|
|
975
986
|
`decode_hypercore_event(log)` take a web3 receipt log or a raw JSON-RPC / indexer
|
|
@@ -991,15 +1002,20 @@ These apply to every caller, type-checked or not. Changes described in full abov
|
|
|
991
1002
|
are listed with a link.
|
|
992
1003
|
|
|
993
1004
|
- **The CLI and the MCP tools take the same arguments.**
|
|
994
|
-
- **MCP inputs:** `chain_id` and `block_number` are
|
|
995
|
-
auto-detected / latest
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1005
|
+
- **MCP inputs:** the vault tools' `chain_id` and every `block_number` are
|
|
1006
|
+
optional and omitted means auto-detected / latest; `market_morpho_blue` and
|
|
1007
|
+
`market_meta_morpho` still require a positive `chain_id`. The `0` sentinel is
|
|
1008
|
+
gone: an optional `0` is rejected with an error naming the argument to omit (it
|
|
1009
|
+
is never read as chain or block 0), so a client that passed `0` omits the
|
|
1010
|
+
argument instead; the market tools' required `chain_id` rejects `0` too and
|
|
1011
|
+
needs the real chain id. The CLI refuses `--block-number 0` and `--chain-id 0`
|
|
1012
|
+
the same way. `server_info(changelog_since=)` is `server_info(since=)` as in
|
|
999
1013
|
`fusion changelog --since`, and `vault_oracle_mapping` takes `max_depth` like
|
|
1000
1014
|
`--max-depth`.
|
|
1001
|
-
- **Chain auto-detection:**
|
|
1002
|
-
chain of the only configured provider
|
|
1015
|
+
- **Chain auto-detection:** the vault commands and tools use the saved vault's
|
|
1016
|
+
chain, else the chain of the only configured provider (the CLI used only the
|
|
1017
|
+
saved vault); `vault_add` uses the only configured provider, and
|
|
1018
|
+
`config_set_provider` asks the provider (`eth_chainId`).
|
|
1003
1019
|
- **CLI options:** every `--block-number` rejects a negative block, and
|
|
1004
1020
|
`fusion market morpho-blue --block` is `--block-number` (`--block` still
|
|
1005
1021
|
works).
|
|
@@ -1104,8 +1120,8 @@ are listed with a link.
|
|
|
1104
1120
|
and small or empty markets could be off by orders of magnitude: expect materially
|
|
1105
1121
|
different numbers where they were wrong.
|
|
1106
1122
|
|
|
1107
|
-
- **MCP `outputSchema` describes every nested block.**
|
|
1108
|
-
byte-identical; the schemas of `vault_info`, `vault_oracle_mapping`,
|
|
1123
|
+
- **MCP `outputSchema` describes every nested block.** This change alone keeps the
|
|
1124
|
+
tool output byte-identical (the other changes in this list still apply); the schemas of `vault_info`, `vault_oracle_mapping`,
|
|
1109
1125
|
`market_morpho_blue` and `market_meta_morpho` replace each free-form object with
|
|
1110
1126
|
the block's own definition: `links` (`VaultLinks`), `deployment`
|
|
1111
1127
|
(`DeploymentModel` or `DeploymentErrorModel`), `share_price` (`SharePriceModel`),
|
|
@@ -1192,4 +1208,6 @@ are listed with a link.
|
|
|
1192
1208
|
Both stay unhashable (`__hash__` is `None`, as before). The freeze is shallow:
|
|
1193
1209
|
the `logs` / `calls` lists themselves can still be mutated.
|
|
1194
1210
|
- Saved config entries are checksummed when loaded; the MCP `vault_add` tool rejects
|
|
1195
|
-
a value that is not an address.
|
|
1211
|
+
a value that is not an address. The MCP vault tools accept a vault address as 3.x
|
|
1212
|
+
did (any letter case, with or without `0x`, surrounding whitespace) and normalize
|
|
1213
|
+
it before the strict SDK parser; only the SDK's `parse_*` functions are strict.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ipor-fusion
|
|
3
|
-
Version: 4.0.0.
|
|
3
|
+
Version: 4.0.0.dev249
|
|
4
4
|
Summary: The IPOR Fusion SDK for Python
|
|
5
5
|
Project-URL: homepage, https://ipor.io
|
|
6
6
|
Project-URL: repository, https://github.com/IPOR-Labs/ipor-fusion.py
|
|
@@ -412,7 +412,8 @@ release; adding one does not.
|
|
|
412
412
|
- **Third-party types** are not re-exported: import `ChecksumAddress` and
|
|
413
413
|
`HexAddress` from `eth_typing`, and `BlockIdentifier`, `Timestamp` and `TxParams`
|
|
414
414
|
from `web3.types`. The SDK's own types (`ChainId`, `Amount`, `PlasmaVaultAddress`,
|
|
415
|
-
...) come from `ipor_fusion` or `ipor_fusion.types
|
|
415
|
+
...) come from `ipor_fusion` or `ipor_fusion.types`; a preview feature's ids
|
|
416
|
+
(`CommandId`, `HyperCoreAsset`, ...) come from its subpackage.
|
|
416
417
|
|
|
417
418
|
`tests/test_public_api.py` snapshots every `__all__` and the names each public
|
|
418
419
|
module keeps by path, so a change to the surface is a deliberate, reviewed edit.
|
|
@@ -489,9 +490,12 @@ import these from their subpackage, and expect changes in a minor release.
|
|
|
489
490
|
| Crosschain fuses (market 54): `StargateCrosschainSupplyFuse`, `StargateCrosschainCommandFuse`, `CcipCrosschainSupplyFuse`, `CcipCrosschainCommandFuse`, `CrosschainClaimFuse`; transport-agnostic bases `CrosschainSupplyFuse` / `CrosschainCommandFuse` with `StargateSendParams` / `CcipSendParams`, plus `Command`, `CrosschainSubstrateLib`, `OptionsBuilder` | `ipor_fusion.crosschain` |
|
|
490
491
|
| HyperCore fuses (market 55): `HyperCoreDepositFuse`, `HyperCoreMarginFuse`, `HyperCoreSendFuse`, `HyperCoreOrderFuse`, `HyperCoreCancelFuse`, `HyperCoreBuilderFeeFuse`, `HyperCoreSubstrates` | `ipor_fusion.hypercore`, with `HyperCoreReader`, `read_hypercore_vault_state` and the event decoders |
|
|
491
492
|
|
|
492
|
-
The mainnet crosschain POC vault uses a keccak-derived market ID, not 54.
|
|
493
|
-
`crosschain_market_id("IPOR_FUSION_CROSSCHAIN_USDC_POC_V1")`
|
|
494
|
-
`
|
|
493
|
+
The mainnet crosschain POC vault uses a keccak-derived market ID, not 54. Pass
|
|
494
|
+
`market_id=crosschain_market_id("IPOR_FUSION_CROSSCHAIN_USDC_POC_V1")` to `open_lane`
|
|
495
|
+
/ `discover_deployment` for that deployment. Both require it explicitly:
|
|
496
|
+
`discover_deployment` reads the market's executor grants; `open_lane` takes an executor
|
|
497
|
+
address and uses the market ID to find the vault's matching fuses unless they are
|
|
498
|
+
passed.
|
|
495
499
|
|
|
496
500
|
### Readers (`ipor_fusion.readers`)
|
|
497
501
|
|
|
@@ -542,15 +546,18 @@ takes the same object.
|
|
|
542
546
|
## Development
|
|
543
547
|
|
|
544
548
|
```bash
|
|
545
|
-
uv sync --all-extras
|
|
549
|
+
uv sync --all-extras --locked # Install dependencies (as CI)
|
|
546
550
|
uv run pytest tests/test_fuse_encoding.py -n auto -v # Unit tests (fast, offline)
|
|
547
|
-
uv run pytest -v -s # All tests
|
|
551
|
+
uv run pytest -v -s # All tests; live ones skip without their provider
|
|
548
552
|
uv run ruff format ./ # Format
|
|
549
553
|
uv run ruff check ./ # Lint
|
|
550
554
|
uv run pyright # Type check
|
|
551
555
|
```
|
|
552
556
|
|
|
553
|
-
|
|
557
|
+
Each integration test runs when its provider URL is in `.env` (eth_simulateV1 at a
|
|
558
|
+
pinned fork block, no local node) and skips otherwise; HyperEVM tests also need
|
|
559
|
+
`HYPEREVM_PROVIDER_URL`, and the source-backed rehearsals a contracts checkout (see
|
|
560
|
+
AGENTS.md):
|
|
554
561
|
|
|
555
562
|
```bash
|
|
556
563
|
cp .env.example .env
|
|
@@ -364,7 +364,8 @@ release; adding one does not.
|
|
|
364
364
|
- **Third-party types** are not re-exported: import `ChecksumAddress` and
|
|
365
365
|
`HexAddress` from `eth_typing`, and `BlockIdentifier`, `Timestamp` and `TxParams`
|
|
366
366
|
from `web3.types`. The SDK's own types (`ChainId`, `Amount`, `PlasmaVaultAddress`,
|
|
367
|
-
...) come from `ipor_fusion` or `ipor_fusion.types
|
|
367
|
+
...) come from `ipor_fusion` or `ipor_fusion.types`; a preview feature's ids
|
|
368
|
+
(`CommandId`, `HyperCoreAsset`, ...) come from its subpackage.
|
|
368
369
|
|
|
369
370
|
`tests/test_public_api.py` snapshots every `__all__` and the names each public
|
|
370
371
|
module keeps by path, so a change to the surface is a deliberate, reviewed edit.
|
|
@@ -441,9 +442,12 @@ import these from their subpackage, and expect changes in a minor release.
|
|
|
441
442
|
| Crosschain fuses (market 54): `StargateCrosschainSupplyFuse`, `StargateCrosschainCommandFuse`, `CcipCrosschainSupplyFuse`, `CcipCrosschainCommandFuse`, `CrosschainClaimFuse`; transport-agnostic bases `CrosschainSupplyFuse` / `CrosschainCommandFuse` with `StargateSendParams` / `CcipSendParams`, plus `Command`, `CrosschainSubstrateLib`, `OptionsBuilder` | `ipor_fusion.crosschain` |
|
|
442
443
|
| HyperCore fuses (market 55): `HyperCoreDepositFuse`, `HyperCoreMarginFuse`, `HyperCoreSendFuse`, `HyperCoreOrderFuse`, `HyperCoreCancelFuse`, `HyperCoreBuilderFeeFuse`, `HyperCoreSubstrates` | `ipor_fusion.hypercore`, with `HyperCoreReader`, `read_hypercore_vault_state` and the event decoders |
|
|
443
444
|
|
|
444
|
-
The mainnet crosschain POC vault uses a keccak-derived market ID, not 54.
|
|
445
|
-
`crosschain_market_id("IPOR_FUSION_CROSSCHAIN_USDC_POC_V1")`
|
|
446
|
-
`
|
|
445
|
+
The mainnet crosschain POC vault uses a keccak-derived market ID, not 54. Pass
|
|
446
|
+
`market_id=crosschain_market_id("IPOR_FUSION_CROSSCHAIN_USDC_POC_V1")` to `open_lane`
|
|
447
|
+
/ `discover_deployment` for that deployment. Both require it explicitly:
|
|
448
|
+
`discover_deployment` reads the market's executor grants; `open_lane` takes an executor
|
|
449
|
+
address and uses the market ID to find the vault's matching fuses unless they are
|
|
450
|
+
passed.
|
|
447
451
|
|
|
448
452
|
### Readers (`ipor_fusion.readers`)
|
|
449
453
|
|
|
@@ -494,15 +498,18 @@ takes the same object.
|
|
|
494
498
|
## Development
|
|
495
499
|
|
|
496
500
|
```bash
|
|
497
|
-
uv sync --all-extras
|
|
501
|
+
uv sync --all-extras --locked # Install dependencies (as CI)
|
|
498
502
|
uv run pytest tests/test_fuse_encoding.py -n auto -v # Unit tests (fast, offline)
|
|
499
|
-
uv run pytest -v -s # All tests
|
|
503
|
+
uv run pytest -v -s # All tests; live ones skip without their provider
|
|
500
504
|
uv run ruff format ./ # Format
|
|
501
505
|
uv run ruff check ./ # Lint
|
|
502
506
|
uv run pyright # Type check
|
|
503
507
|
```
|
|
504
508
|
|
|
505
|
-
|
|
509
|
+
Each integration test runs when its provider URL is in `.env` (eth_simulateV1 at a
|
|
510
|
+
pinned fork block, no local node) and skips otherwise; HyperEVM tests also need
|
|
511
|
+
`HYPEREVM_PROVIDER_URL`, and the source-backed rehearsals a contracts checkout (see
|
|
512
|
+
AGENTS.md):
|
|
506
513
|
|
|
507
514
|
```bash
|
|
508
515
|
cp .env.example .env
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"""`fusion market` command group — protocol-level market inspection.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
`morpho-blue <marketId>` fetches a Morpho Blue market's parameters and state
|
|
4
|
+
(loan/collateral/oracle/IRM/LLTV, totals, liquidity, APYs) plus the MetaMorpho
|
|
5
|
+
vaults supplying it (current allocation, supply caps, and PublicAllocator flow
|
|
6
|
+
caps + fees), combining on-chain reads via `MorphoReader` with the Morpho public
|
|
7
|
+
GraphQL API. `meta-morpho <vault>` inspects a MetaMorpho V1 or Vault V2 from the
|
|
8
|
+
API: roles, fees, adapters or allocations and caps.
|
|
8
9
|
"""
|
|
9
10
|
|
|
10
11
|
from __future__ import annotations
|
|
@@ -59,6 +59,7 @@ from ipor_fusion.readers.morpho import MorphoReader, morpho_blue_address
|
|
|
59
59
|
from ipor_fusion.readers.oracle_mapping import build_oracle_mapping
|
|
60
60
|
from ipor_fusion.types import (
|
|
61
61
|
ChainId,
|
|
62
|
+
PlasmaVaultAddress,
|
|
62
63
|
parse_morpho_market_id,
|
|
63
64
|
parse_plasma_vault_address,
|
|
64
65
|
)
|
|
@@ -100,6 +101,12 @@ def _resolve_provider(cfg: FusionConfig, chain_id: ChainId) -> str:
|
|
|
100
101
|
)
|
|
101
102
|
|
|
102
103
|
|
|
104
|
+
def _vault_arg(raw: str) -> PlasmaVaultAddress:
|
|
105
|
+
"""A vault address as a tool caller sends it: surrounding whitespace, a
|
|
106
|
+
missing ``0x`` and any letter case are accepted, as in 3.x."""
|
|
107
|
+
return parse_plasma_vault_address(Web3.to_checksum_address(raw.strip()))
|
|
108
|
+
|
|
109
|
+
|
|
103
110
|
def _resolve_chain_id(
|
|
104
111
|
cfg: FusionConfig, vault_address: str, chain_id: ChainId | None
|
|
105
112
|
) -> ChainId:
|
|
@@ -210,12 +217,12 @@ def vault_info(
|
|
|
210
217
|
etc.).
|
|
211
218
|
"""
|
|
212
219
|
cfg = load_config()
|
|
213
|
-
|
|
220
|
+
checksum = _vault_arg(vault_address)
|
|
221
|
+
chain_id = _resolve_chain_id(cfg, checksum, chain_id)
|
|
214
222
|
# Fail fast (before any RPC) on chains the vault tooling can't handle;
|
|
215
223
|
# UnsupportedChainError doubles as ValueError so FastMCP surfaces it.
|
|
216
224
|
ensure_supported_chain(chain_id)
|
|
217
225
|
ctx, effective_block = _build_ctx(cfg, chain_id, block_number)
|
|
218
|
-
checksum = parse_plasma_vault_address(vault_address)
|
|
219
226
|
|
|
220
227
|
# Cheap single-call probe: raises the typed ContractNotFoundError /
|
|
221
228
|
# NotPlasmaVaultError ("not a vault" in both revert and empty-return
|
|
@@ -257,10 +264,10 @@ def vault_validate(
|
|
|
257
264
|
consistent. It reads about as much as vault_info and takes about as long.
|
|
258
265
|
"""
|
|
259
266
|
cfg = load_config()
|
|
260
|
-
|
|
267
|
+
checksum = _vault_arg(vault_address)
|
|
268
|
+
chain_id = _resolve_chain_id(cfg, checksum, chain_id)
|
|
261
269
|
ensure_supported_chain(chain_id)
|
|
262
270
|
ctx, effective_block = _build_ctx(cfg, chain_id, block_number)
|
|
263
|
-
checksum = parse_plasma_vault_address(vault_address)
|
|
264
271
|
|
|
265
272
|
# Same cheap probe as vault_info: "not a vault" fails before the fetch.
|
|
266
273
|
resolve_access_manager(ctx, checksum)
|
|
@@ -323,12 +330,12 @@ def vault_role_accounts(
|
|
|
323
330
|
"""
|
|
324
331
|
cfg = load_config()
|
|
325
332
|
role_id = None if role is None else Roles.resolve(role)
|
|
326
|
-
|
|
333
|
+
checksum = _vault_arg(vault_address)
|
|
334
|
+
chain_id = _resolve_chain_id(cfg, checksum, chain_id)
|
|
327
335
|
# Fail fast (before any RPC) on chains the vault tooling is not
|
|
328
336
|
# validated on.
|
|
329
337
|
ensure_supported_chain(chain_id)
|
|
330
338
|
ctx, _ = _build_ctx(cfg, chain_id, block_number)
|
|
331
|
-
checksum = parse_plasma_vault_address(vault_address)
|
|
332
339
|
|
|
333
340
|
access_manager = resolve_access_manager(ctx, checksum)
|
|
334
341
|
accounts = (
|
|
@@ -408,12 +415,12 @@ def vault_oracle_mapping(
|
|
|
408
415
|
'events'). Historical blocks require an archive node.
|
|
409
416
|
"""
|
|
410
417
|
cfg = load_config()
|
|
411
|
-
|
|
418
|
+
checksum = _vault_arg(vault_address)
|
|
419
|
+
chain_id = _resolve_chain_id(cfg, checksum, chain_id)
|
|
412
420
|
# The asset-source event replay scans logs from block 0 — fail fast
|
|
413
421
|
# (before any RPC) on chains the vault tooling is not validated on.
|
|
414
422
|
ensure_supported_chain(chain_id)
|
|
415
423
|
ctx, _ = _build_ctx(cfg, chain_id, block_number)
|
|
416
|
-
checksum = parse_plasma_vault_address(vault_address)
|
|
417
424
|
|
|
418
425
|
# The event-replay fallback and the output both need a concrete block
|
|
419
426
|
# number, so resolve "latest" up front and pin the context to it.
|
|
@@ -464,7 +471,7 @@ def vault_add(
|
|
|
464
471
|
address: Vault address (required).
|
|
465
472
|
label: Human-readable label (fetched from on-chain name() if empty).
|
|
466
473
|
"""
|
|
467
|
-
checksum =
|
|
474
|
+
checksum = _vault_arg(address)
|
|
468
475
|
cfg = load_config()
|
|
469
476
|
|
|
470
477
|
if chain_id is None:
|
|
@@ -26,6 +26,7 @@ from ipor_fusion.mcp.models import (
|
|
|
26
26
|
WithdrawManagerDetails,
|
|
27
27
|
)
|
|
28
28
|
from ipor_fusion.mcp.server import (
|
|
29
|
+
_vault_arg,
|
|
29
30
|
config_set_etherscan_key,
|
|
30
31
|
config_set_provider,
|
|
31
32
|
config_show,
|
|
@@ -39,6 +40,7 @@ from ipor_fusion.mcp.server import (
|
|
|
39
40
|
vault_oracle_mapping,
|
|
40
41
|
vault_remove,
|
|
41
42
|
vault_role_accounts,
|
|
43
|
+
vault_validate,
|
|
42
44
|
)
|
|
43
45
|
from ipor_fusion.morpho_api import (
|
|
44
46
|
MorphoApiError,
|
|
@@ -1082,3 +1084,77 @@ class TestMarketMetaMorpho:
|
|
|
1082
1084
|
def test_unknown_vault_errors(self, _fetch):
|
|
1083
1085
|
with pytest.raises(MorphoApiError, match="not found"):
|
|
1084
1086
|
market_meta_morpho(vault_address=_VAULT, chain_id=1)
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
class TestVaultAddressArgument:
|
|
1090
|
+
"""Tool callers send addresses as 3.x accepted them; the server normalizes
|
|
1091
|
+
before the strict SDK parser."""
|
|
1092
|
+
|
|
1093
|
+
VAULT = "0x43ee0243ea8cf02f7087d8b16c8d2007cc9c7ca2"
|
|
1094
|
+
|
|
1095
|
+
@pytest.mark.parametrize(
|
|
1096
|
+
"raw",
|
|
1097
|
+
[
|
|
1098
|
+
VAULT,
|
|
1099
|
+
VAULT.upper().replace("0X", "0x"),
|
|
1100
|
+
VAULT[2:],
|
|
1101
|
+
f" {VAULT} ",
|
|
1102
|
+
Web3.to_checksum_address(VAULT),
|
|
1103
|
+
],
|
|
1104
|
+
)
|
|
1105
|
+
def test_accepts_any_spelling(self, raw: str):
|
|
1106
|
+
assert _vault_arg(raw) == Web3.to_checksum_address(self.VAULT)
|
|
1107
|
+
|
|
1108
|
+
@pytest.mark.parametrize("raw", ["", "0x1234", "not an address", "0x" + "g" * 40])
|
|
1109
|
+
def test_rejects_non_addresses(self, raw: str):
|
|
1110
|
+
with pytest.raises(ValueError):
|
|
1111
|
+
_vault_arg(raw)
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
class TestVaultAddressResolvesSavedChain:
|
|
1115
|
+
"""Every spelling the tools accept finds the saved vault's chain."""
|
|
1116
|
+
|
|
1117
|
+
@staticmethod
|
|
1118
|
+
def _config(providers: list[int]):
|
|
1119
|
+
from ipor_fusion.cli.config_store import FusionConfig, VaultEntry
|
|
1120
|
+
|
|
1121
|
+
return FusionConfig(
|
|
1122
|
+
providers={str(c): "https://rpc.example.com" for c in providers},
|
|
1123
|
+
vaults=[VaultEntry(address=_SAVED_VAULT, label="Test", chain_id=1)],
|
|
1124
|
+
)
|
|
1125
|
+
|
|
1126
|
+
@pytest.mark.parametrize(
|
|
1127
|
+
"spelling", [f" {_SAVED_VAULT} ", _SAVED_VAULT[2:], _SAVED_VAULT.upper()]
|
|
1128
|
+
)
|
|
1129
|
+
@pytest.mark.parametrize(
|
|
1130
|
+
"tool", [vault_info, vault_validate, vault_role_accounts, vault_oracle_mapping]
|
|
1131
|
+
)
|
|
1132
|
+
def test_saved_chain_wins_over_other_providers(self, tool, spelling: str):
|
|
1133
|
+
seen: list[int] = []
|
|
1134
|
+
|
|
1135
|
+
def stop(_cfg, chain_id, _block):
|
|
1136
|
+
seen.append(chain_id)
|
|
1137
|
+
raise RuntimeError("stop")
|
|
1138
|
+
|
|
1139
|
+
with (
|
|
1140
|
+
patch(
|
|
1141
|
+
"ipor_fusion.mcp.server.load_config",
|
|
1142
|
+
autospec=True,
|
|
1143
|
+
return_value=self._config([1, 8453]),
|
|
1144
|
+
),
|
|
1145
|
+
patch("ipor_fusion.mcp.server._build_ctx", autospec=True, side_effect=stop),
|
|
1146
|
+
pytest.raises(RuntimeError, match="stop"),
|
|
1147
|
+
):
|
|
1148
|
+
tool(spelling)
|
|
1149
|
+
assert seen == [1]
|
|
1150
|
+
|
|
1151
|
+
def test_missing_saved_chain_provider_is_reported_not_substituted(self):
|
|
1152
|
+
with (
|
|
1153
|
+
patch(
|
|
1154
|
+
"ipor_fusion.mcp.server.load_config",
|
|
1155
|
+
autospec=True,
|
|
1156
|
+
return_value=self._config([8453]),
|
|
1157
|
+
),
|
|
1158
|
+
pytest.raises(ValueError, match="No provider for chain 1"),
|
|
1159
|
+
):
|
|
1160
|
+
vault_info(f" {_SAVED_VAULT[2:]} ")
|
|
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
|