ipor-fusion 4.0.0.dev200__tar.gz → 4.0.0.dev206__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.dev200 → ipor_fusion-4.0.0.dev206}/.github/workflows/cd.yml +2 -1
- ipor_fusion-4.0.0.dev206/.github/workflows/ci.yml +55 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.github/workflows/python-build.yml +15 -4
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/AGENTS.md +17 -4
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/pyproject.toml +2 -4
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/context.py +1 -1
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/fusion_factory.py +1 -3
- ipor_fusion-4.0.0.dev206/tests/_live.py +67 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/conftest.py +11 -13
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_readiness_selection.py +2 -1
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_solidity_mirrors.py +3 -2
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_vault_info_onchain_base.py +11 -23
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +4 -19
- ipor_fusion-4.0.0.dev200/.github/workflows/ci.yml +0 -32
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/MIGRATION_4.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/README.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/simulation_result.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/mcp/server.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/vault_data.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_event_args.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_fake_rpc.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_golden.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_oracle_mapping_fake.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_blue.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/simulate_v1_request.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/fetched.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/full.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/full.txt +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_market_golden.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_oracle_mapping_golden.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_public_api.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulation_errors.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_simulation_observation.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_vault_data_block.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_vault_info_fetched_golden.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_vault_reconciliation_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/tests/typed_client/rejected.py +0 -0
- {ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/uv.lock +0 -0
|
@@ -12,12 +12,13 @@ jobs:
|
|
|
12
12
|
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
|
13
13
|
|
|
14
14
|
build:
|
|
15
|
-
needs: notify
|
|
16
15
|
uses: ./.github/workflows/python-build.yml
|
|
17
16
|
secrets:
|
|
18
17
|
ETHEREUM_PROVIDER_URL: ${{ secrets.ETHEREUM_PROVIDER_URL }}
|
|
19
18
|
ARBITRUM_PROVIDER_URL: ${{ secrets.ARBITRUM_PROVIDER_URL }}
|
|
20
19
|
BASE_PROVIDER_URL: ${{ secrets.BASE_PROVIDER_URL }}
|
|
20
|
+
with:
|
|
21
|
+
require-live: ETHEREUM_PROVIDER_URL,ARBITRUM_PROVIDER_URL,BASE_PROVIDER_URL,GITHUB
|
|
21
22
|
|
|
22
23
|
report:
|
|
23
24
|
if: ${{ always() }}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
branches:
|
|
6
|
+
- "**"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
notify:
|
|
10
|
+
uses: ./.github/workflows/notify-slack.yml
|
|
11
|
+
secrets:
|
|
12
|
+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
|
13
|
+
|
|
14
|
+
# No secrets: what the code proves offline, on every supported Python.
|
|
15
|
+
offline:
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
20
|
+
uses: ./.github/workflows/python-build.yml
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
format-code-enabled: ${{ matrix.python-version == '3.12' }}
|
|
24
|
+
static-code-analysis-enabled: ${{ matrix.python-version == '3.12' }}
|
|
25
|
+
build-enabled: ${{ matrix.python-version == '3.12' }}
|
|
26
|
+
coverage-artifact-name: coverage-offline-${{ matrix.python-version }}
|
|
27
|
+
|
|
28
|
+
# Live providers, for pull requests from this repository only (a fork gets
|
|
29
|
+
# no secrets); a provider or GitHub outage fails it instead of skipping.
|
|
30
|
+
live:
|
|
31
|
+
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
|
|
32
|
+
uses: ./.github/workflows/python-build.yml
|
|
33
|
+
secrets:
|
|
34
|
+
ETHEREUM_PROVIDER_URL: ${{ secrets.ETHEREUM_PROVIDER_URL }}
|
|
35
|
+
ARBITRUM_PROVIDER_URL: ${{ secrets.ARBITRUM_PROVIDER_URL }}
|
|
36
|
+
BASE_PROVIDER_URL: ${{ secrets.BASE_PROVIDER_URL }}
|
|
37
|
+
with:
|
|
38
|
+
format-code-enabled: false
|
|
39
|
+
static-code-analysis-enabled: false
|
|
40
|
+
build-enabled: false
|
|
41
|
+
coverage-artifact-name: coverage-live
|
|
42
|
+
require-live: ETHEREUM_PROVIDER_URL,ARBITRUM_PROVIDER_URL,BASE_PROVIDER_URL,GITHUB
|
|
43
|
+
|
|
44
|
+
report:
|
|
45
|
+
if: ${{ always() }}
|
|
46
|
+
needs:
|
|
47
|
+
- notify
|
|
48
|
+
- offline
|
|
49
|
+
- live
|
|
50
|
+
uses: ./.github/workflows/report-slack.yml
|
|
51
|
+
secrets:
|
|
52
|
+
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
|
53
|
+
with:
|
|
54
|
+
success: ${{ needs.offline.result == 'success' && contains(fromJSON('["success", "skipped"]'), needs.live.result) }}
|
|
55
|
+
slack-status-msg-id: ${{ needs.notify.outputs.slack-status-msg-id }}
|
|
@@ -5,11 +5,11 @@ on:
|
|
|
5
5
|
|
|
6
6
|
secrets:
|
|
7
7
|
ARBITRUM_PROVIDER_URL:
|
|
8
|
-
required:
|
|
8
|
+
required: false
|
|
9
9
|
BASE_PROVIDER_URL:
|
|
10
|
-
required:
|
|
10
|
+
required: false
|
|
11
11
|
ETHEREUM_PROVIDER_URL:
|
|
12
|
-
required:
|
|
12
|
+
required: false
|
|
13
13
|
|
|
14
14
|
inputs:
|
|
15
15
|
python-version:
|
|
@@ -42,6 +42,16 @@ on:
|
|
|
42
42
|
type: boolean
|
|
43
43
|
default: true
|
|
44
44
|
required: false
|
|
45
|
+
coverage-artifact-name:
|
|
46
|
+
description: "Name of the uploaded coverage artifact (unique per call in a run)"
|
|
47
|
+
type: string
|
|
48
|
+
default: coverage-report
|
|
49
|
+
required: false
|
|
50
|
+
require-live:
|
|
51
|
+
description: "Comma-separated live sources whose tests must run, not skip (tests/_live.py)"
|
|
52
|
+
type: string
|
|
53
|
+
default: ""
|
|
54
|
+
required: false
|
|
45
55
|
|
|
46
56
|
jobs:
|
|
47
57
|
python:
|
|
@@ -93,6 +103,7 @@ jobs:
|
|
|
93
103
|
ETHEREUM_PROVIDER_URL: ${{ secrets.ETHEREUM_PROVIDER_URL }}
|
|
94
104
|
ARBITRUM_PROVIDER_URL: ${{ secrets.ARBITRUM_PROVIDER_URL }}
|
|
95
105
|
BASE_PROVIDER_URL: ${{ secrets.BASE_PROVIDER_URL }}
|
|
106
|
+
IPOR_FUSION_REQUIRE_LIVE: ${{ inputs.require-live }}
|
|
96
107
|
id: tests
|
|
97
108
|
|
|
98
109
|
- name: Coverage summary
|
|
@@ -104,6 +115,6 @@ jobs:
|
|
|
104
115
|
if: inputs.test-enabled && always() && steps.tests.outcome != 'skipped'
|
|
105
116
|
uses: actions/upload-artifact@v4
|
|
106
117
|
with:
|
|
107
|
-
name: coverage-
|
|
118
|
+
name: ${{ inputs.coverage-artifact-name }}
|
|
108
119
|
path: coverage.xml
|
|
109
120
|
|
|
@@ -27,7 +27,7 @@ uv sync --all-extras --locked # install, same as
|
|
|
27
27
|
uv run ruff format ./ # format (CI runs --check)
|
|
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
|
-
uv run pytest # all tests + coverage gate (fail_under =
|
|
30
|
+
uv run pytest # all tests + coverage gate (fail_under = 98, mcp/ included)
|
|
31
31
|
uv run pytest -m "cli or mcp" --no-cov # fast offline subset
|
|
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
|
|
@@ -54,13 +54,26 @@ the sequence in `.github/workflows/python-build.yml`. When ruff `C901` trips,
|
|
|
54
54
|
extract helpers, never suppress.
|
|
55
55
|
|
|
56
56
|
**Offline vs network.** `test_cli_*` and `test_mcp_*` need no network
|
|
57
|
-
(auto-tagged `cli` / `mcp` in `conftest.py
|
|
57
|
+
(auto-tagged `cli` / `mcp` in `conftest.py`, `test_examples_*` `examples`;
|
|
58
|
+
everything else is `sdk`). Most `sdk` tests are offline too: the suite with no
|
|
59
|
+
provider set still clears the coverage gate.
|
|
58
60
|
Integration tests (`test_simulate_*`, `test_vault_info_onchain_*`) run against
|
|
59
61
|
live RPCs via `eth_simulateV1`, no Docker or Anvil (`ANVIL_WALLET` is just a
|
|
60
62
|
named address constant). They auto-skip unless `ETHEREUM_PROVIDER_URL`,
|
|
61
63
|
`BASE_PROVIDER_URL` and `ARBITRUM_PROVIDER_URL` are set (`.env` is loaded via
|
|
62
|
-
python-dotenv) and the provider supports `eth_simulateV1`.
|
|
63
|
-
|
|
64
|
+
python-dotenv) and the provider supports `eth_simulateV1`. Every such gate goes
|
|
65
|
+
through `tests/_live.py` (`provider_url`, `archive_context`, `unavailable`): it
|
|
66
|
+
skips locally and fails when the source is named in `IPOR_FUSION_REQUIRE_LIVE`
|
|
67
|
+
(comma-separated env var names, `GITHUB` for the Solidity mirrors). CI
|
|
68
|
+
(`ci.yml`) runs an offline job without secrets on Python 3.11, 3.12 and 3.13
|
|
69
|
+
and, for pull requests from this repository, a live job with the three
|
|
70
|
+
provider secrets that requires all of them and GitHub: a skip for one of those
|
|
71
|
+
sources being unavailable is a failure there (state-dependent skips such as a
|
|
72
|
+
pilot vault's preconditions remain skips, and the offline job still reads the
|
|
73
|
+
public Solidity sources from GitHub). Skip only for an unavailable source; an
|
|
74
|
+
exception from the
|
|
75
|
+
SDK is a test failure, never a skip. Never print `.env` or a provider URL: they
|
|
76
|
+
embed API keys, so skip and fail messages carry the exception type only.
|
|
64
77
|
`HYPEREVM_PROVIDER_URL` is used by the HyperEVM lifecycle/deployment tests and
|
|
65
78
|
the readiness script; general PR CI does not supply it.
|
|
66
79
|
`test_simulate_crosschain_hyperevm.py` rehearses Arbitrum → HyperEVM on pinned blocks,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ipor-fusion"
|
|
3
|
-
version = "4.0.0.
|
|
3
|
+
version = "4.0.0.dev206"
|
|
4
4
|
description = "The IPOR Fusion SDK for Python"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Adam Mydlarz", email = "amydlarz@gmail.com" },
|
|
@@ -123,12 +123,10 @@ executionEnvironments = [
|
|
|
123
123
|
[tool.coverage.run]
|
|
124
124
|
source = ["src/ipor_fusion"]
|
|
125
125
|
data_file = ".coverage_data/.coverage"
|
|
126
|
-
omit = ["src/ipor_fusion/mcp/*"]
|
|
127
126
|
|
|
128
127
|
[tool.coverage.report]
|
|
129
128
|
show_missing = true
|
|
130
|
-
fail_under =
|
|
131
|
-
omit = ["src/ipor_fusion/mcp/*"]
|
|
129
|
+
fail_under = 98
|
|
132
130
|
|
|
133
131
|
[tool.semantic_release]
|
|
134
132
|
# Runs inside the python-semantic-release Docker container, not on the runner
|
{ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/core/fusion_factory.py
RENAMED
|
@@ -79,9 +79,7 @@ class FusionInstance:
|
|
|
79
79
|
price_manager: ChecksumAddress
|
|
80
80
|
|
|
81
81
|
@classmethod
|
|
82
|
-
def from_dict(
|
|
83
|
-
cls, data: Mapping[str, object]
|
|
84
|
-
) -> FusionInstance:
|
|
82
|
+
def from_dict(cls, data: Mapping[str, object]) -> FusionInstance:
|
|
85
83
|
"""Rebuild an instance from its JSON form (``dataclasses.asdict``),
|
|
86
84
|
parsing every field: role addresses through their parsers, the rest
|
|
87
85
|
checksummed, integers and strings type-checked. Raises ``ValueError``
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Gates of the tests that need a live provider or network source.
|
|
2
|
+
|
|
3
|
+
Locally a missing or unreachable source skips the test. A run that names the
|
|
4
|
+
source in ``IPOR_FUSION_REQUIRE_LIVE`` (comma-separated: provider env var names
|
|
5
|
+
such as ``BASE_PROVIDER_URL``, or ``GITHUB`` for the Solidity mirrors) fails
|
|
6
|
+
instead, so a green CI run means the live checks ran rather than skipped.
|
|
7
|
+
Messages carry the exception type only: provider URLs embed API keys.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import os
|
|
13
|
+
from typing import NoReturn
|
|
14
|
+
|
|
15
|
+
import pytest
|
|
16
|
+
import requests
|
|
17
|
+
from web3 import Web3
|
|
18
|
+
from web3.exceptions import Web3Exception
|
|
19
|
+
|
|
20
|
+
from ipor_fusion import Web3Context
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def required() -> frozenset[str]:
|
|
24
|
+
return frozenset(
|
|
25
|
+
name.strip()
|
|
26
|
+
for name in os.environ.get("IPOR_FUSION_REQUIRE_LIVE", "").split(",")
|
|
27
|
+
if name.strip()
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def unavailable(source: str, reason: str) -> NoReturn:
|
|
32
|
+
"""Skip, or fail when this run requires ``source``."""
|
|
33
|
+
if source in required():
|
|
34
|
+
pytest.fail(f"{source} is required in this run: {reason}", pytrace=False)
|
|
35
|
+
pytest.skip(reason)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def provider_url(env_var: str) -> str:
|
|
39
|
+
url = os.environ.get(env_var)
|
|
40
|
+
if not url:
|
|
41
|
+
unavailable(env_var, f"{env_var} not set")
|
|
42
|
+
return url
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# A provider that cannot be reached, refuses the key, or has pruned the state.
|
|
46
|
+
_INFRA_ERRORS = (Web3Exception, requests.RequestException, OSError)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def archive_context(env_var: str, block: int, contract: str) -> Web3Context:
|
|
50
|
+
"""A context pinned to ``block`` on the provider in ``env_var``, once it
|
|
51
|
+
has connected and served ``contract``'s code at that block (historical
|
|
52
|
+
state, not just the header); later SDK errors are test failures, not
|
|
53
|
+
infrastructure."""
|
|
54
|
+
url = provider_url(env_var)
|
|
55
|
+
# The failure is reported outside the except block: a chained traceback
|
|
56
|
+
# would print the request URL, which embeds the API key.
|
|
57
|
+
failure: str | None = None
|
|
58
|
+
try:
|
|
59
|
+
ctx = Web3Context.from_url(url)
|
|
60
|
+
code = ctx.web3.eth.get_code(Web3.to_checksum_address(contract), block)
|
|
61
|
+
except _INFRA_ERRORS as exc:
|
|
62
|
+
failure = type(exc).__name__
|
|
63
|
+
if failure is not None:
|
|
64
|
+
unavailable(env_var, f"{env_var} cannot serve state at {block}: {failure}")
|
|
65
|
+
if not code:
|
|
66
|
+
unavailable(env_var, f"{env_var} returned no code for {contract} at {block}")
|
|
67
|
+
return ctx.at_block(block)
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import importlib.util
|
|
2
|
-
import os
|
|
3
2
|
from collections.abc import Callable
|
|
4
3
|
from pathlib import Path
|
|
5
4
|
from types import ModuleType
|
|
6
5
|
from unittest.mock import patch
|
|
7
6
|
|
|
8
7
|
import pytest
|
|
8
|
+
from _live import provider_url, unavailable
|
|
9
9
|
from _multicall import SequentialMulticall
|
|
10
10
|
from dotenv import load_dotenv
|
|
11
11
|
from web3 import Web3
|
|
@@ -72,40 +72,38 @@ def pytest_collection_modifyitems(config, items):
|
|
|
72
72
|
|
|
73
73
|
|
|
74
74
|
def _connected_web3(env_var: str) -> Web3:
|
|
75
|
-
"""Build a Web3 client from `env_var`; skip the test if missing/unreachable
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
pytest.skip(f"{env_var} not set")
|
|
79
|
-
w3 = Web3(Web3.HTTPProvider(url))
|
|
75
|
+
"""Build a Web3 client from `env_var`; skip the test if missing/unreachable
|
|
76
|
+
(fail when the run requires it, see `_live`)."""
|
|
77
|
+
w3 = Web3(Web3.HTTPProvider(provider_url(env_var)))
|
|
80
78
|
if not w3.is_connected():
|
|
81
|
-
|
|
79
|
+
unavailable(env_var, f"cannot reach RPC at {env_var}")
|
|
82
80
|
return w3
|
|
83
81
|
|
|
84
82
|
|
|
85
|
-
def _ensure_simulate_v1(web3: Web3) -> None:
|
|
83
|
+
def _ensure_simulate_v1(web3: Web3, env_var: str) -> None:
|
|
86
84
|
"""Skip if the provider does not implement `eth_simulateV1`."""
|
|
87
85
|
if not is_simulate_v1_supported(web3):
|
|
88
|
-
|
|
86
|
+
unavailable(env_var, f"{env_var} does not support eth_simulateV1")
|
|
89
87
|
|
|
90
88
|
|
|
91
89
|
@pytest.fixture(scope="session")
|
|
92
90
|
def web3_eth() -> Web3:
|
|
93
91
|
w3 = _connected_web3("ETHEREUM_PROVIDER_URL")
|
|
94
|
-
_ensure_simulate_v1(w3)
|
|
92
|
+
_ensure_simulate_v1(w3, "ETHEREUM_PROVIDER_URL")
|
|
95
93
|
return w3
|
|
96
94
|
|
|
97
95
|
|
|
98
96
|
@pytest.fixture(scope="session")
|
|
99
97
|
def web3_base() -> Web3:
|
|
100
98
|
w3 = _connected_web3("BASE_PROVIDER_URL")
|
|
101
|
-
_ensure_simulate_v1(w3)
|
|
99
|
+
_ensure_simulate_v1(w3, "BASE_PROVIDER_URL")
|
|
102
100
|
return w3
|
|
103
101
|
|
|
104
102
|
|
|
105
103
|
@pytest.fixture(scope="session")
|
|
106
104
|
def web3_arb() -> Web3:
|
|
107
105
|
w3 = _connected_web3("ARBITRUM_PROVIDER_URL")
|
|
108
|
-
_ensure_simulate_v1(w3)
|
|
106
|
+
_ensure_simulate_v1(w3, "ARBITRUM_PROVIDER_URL")
|
|
109
107
|
return w3
|
|
110
108
|
|
|
111
109
|
|
|
@@ -113,5 +111,5 @@ def web3_arb() -> Web3:
|
|
|
113
111
|
def web3_hyperevm() -> Web3:
|
|
114
112
|
"""HyperEVM simulation fixture; general PR CI does not supply its RPC secret."""
|
|
115
113
|
w3 = _connected_web3("HYPEREVM_PROVIDER_URL")
|
|
116
|
-
_ensure_simulate_v1(w3)
|
|
114
|
+
_ensure_simulate_v1(w3, "HYPEREVM_PROVIDER_URL")
|
|
117
115
|
return w3
|
|
@@ -22,7 +22,8 @@ pytest_plugins = ["pytester"]
|
|
|
22
22
|
def test_readiness_requires_explicit_opt_in(pytester, args, passed, deselected):
|
|
23
23
|
pytester.makeconftest(Path(__file__).with_name("conftest.py").read_text())
|
|
24
24
|
pytester.makepyfile(
|
|
25
|
-
_multicall=Path(__file__).with_name("_multicall.py").read_text()
|
|
25
|
+
_multicall=Path(__file__).with_name("_multicall.py").read_text(),
|
|
26
|
+
_live=Path(__file__).with_name("_live.py").read_text(),
|
|
26
27
|
)
|
|
27
28
|
pytester.makeini("[pytest]\nmarkers =\n sdk\n cli\n mcp\n readiness\n")
|
|
28
29
|
pytester.makepyfile(
|
|
@@ -14,6 +14,7 @@ from functools import cache
|
|
|
14
14
|
|
|
15
15
|
import pytest
|
|
16
16
|
import requests
|
|
17
|
+
from _live import unavailable
|
|
17
18
|
from eth_utils import function_signature_to_4byte_selector
|
|
18
19
|
|
|
19
20
|
from ipor_fusion.config.roles import Roles
|
|
@@ -58,11 +59,11 @@ def _solidity_source(path: str) -> str:
|
|
|
58
59
|
try:
|
|
59
60
|
resp = requests.get(url, timeout=15)
|
|
60
61
|
except requests.RequestException as exc:
|
|
61
|
-
|
|
62
|
+
unavailable("GITHUB", f"cannot fetch {path} from GitHub: {type(exc).__name__}")
|
|
62
63
|
if resp.status_code == 404:
|
|
63
64
|
pytest.fail(f"{url} not found — wrong pinned ref or moved file")
|
|
64
65
|
if resp.status_code != 200:
|
|
65
|
-
|
|
66
|
+
unavailable("GITHUB", f"GitHub returned HTTP {resp.status_code} for {path}")
|
|
66
67
|
return resp.text
|
|
67
68
|
|
|
68
69
|
|
|
@@ -17,11 +17,10 @@ historical block requires an archive node.
|
|
|
17
17
|
|
|
18
18
|
from __future__ import annotations
|
|
19
19
|
|
|
20
|
-
import os
|
|
21
20
|
from collections import Counter
|
|
22
21
|
from unittest.mock import patch
|
|
23
22
|
|
|
24
|
-
import
|
|
23
|
+
from _live import archive_context, provider_url
|
|
25
24
|
from web3 import Web3
|
|
26
25
|
from web3.providers.rpc import HTTPProvider
|
|
27
26
|
|
|
@@ -35,15 +34,8 @@ EXPECTED_IDLE_USDC = 10 * 10**6 # 10 USDC (6 decimals) sitting idle on the vaul
|
|
|
35
34
|
|
|
36
35
|
|
|
37
36
|
def test_idle_underlying_reconciles_on_real_base_vault():
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
pytest.skip("BASE_PROVIDER_URL not set")
|
|
41
|
-
|
|
42
|
-
try: # pylint: disable=broad-except
|
|
43
|
-
validation = validate_vault(Web3Context.from_url(url), VAULT, block=BLOCK)
|
|
44
|
-
except Exception as exc: # pylint: disable=broad-except
|
|
45
|
-
# Infra problem (provider unreachable or non-archive) — skip, don't fail.
|
|
46
|
-
pytest.skip(f"BASE on-chain read failed (provider missing/non-archive?): {exc}")
|
|
37
|
+
ctx = archive_context("BASE_PROVIDER_URL", BLOCK, VAULT)
|
|
38
|
+
validation = validate_vault(ctx, VAULT, block=BLOCK)
|
|
47
39
|
|
|
48
40
|
# Sanity: confirm we are reading the expected vault/chain state at this block.
|
|
49
41
|
recon = validation.reconciliation
|
|
@@ -64,9 +56,8 @@ MAX_ETH_CALLS = 20
|
|
|
64
56
|
|
|
65
57
|
|
|
66
58
|
def test_fetch_stays_within_round_trip_budget():
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
pytest.skip("BASE_PROVIDER_URL not set")
|
|
59
|
+
archive_context("BASE_PROVIDER_URL", BLOCK, VAULT) # skips without an archive
|
|
60
|
+
url = provider_url("BASE_PROVIDER_URL")
|
|
70
61
|
|
|
71
62
|
methods: Counter[str] = Counter()
|
|
72
63
|
make_request = HTTPProvider.make_request
|
|
@@ -75,15 +66,12 @@ def test_fetch_stays_within_round_trip_budget():
|
|
|
75
66
|
methods[method] += 1
|
|
76
67
|
return make_request(provider, method, params)
|
|
77
68
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
data = fetch_vault_data(ctx, VAULT, block=BLOCK)
|
|
85
|
-
except Exception as exc: # pylint: disable=broad-except
|
|
86
|
-
pytest.skip(f"BASE on-chain read failed (provider missing/non-archive?): {exc}")
|
|
69
|
+
# web3 binds make_request when the provider is built, so the context
|
|
70
|
+
# must be created under the patch for any request to be counted.
|
|
71
|
+
with patch.object(HTTPProvider, "make_request", counting):
|
|
72
|
+
ctx = Web3Context.from_url(url)
|
|
73
|
+
methods.clear()
|
|
74
|
+
data = fetch_vault_data(ctx, VAULT, block=BLOCK)
|
|
87
75
|
|
|
88
76
|
assert data.total_assets == EXPECTED_IDLE_USDC
|
|
89
77
|
assert methods["eth_call"] > 0, "requests were not counted"
|
|
@@ -16,12 +16,10 @@ code under test runs unguarded, so a regression fails instead of skipping.
|
|
|
16
16
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
|
-
import
|
|
20
|
-
|
|
21
|
-
import pytest
|
|
19
|
+
from _live import archive_context
|
|
22
20
|
from web3 import Web3
|
|
23
21
|
|
|
24
|
-
from ipor_fusion import PlasmaVault
|
|
22
|
+
from ipor_fusion import PlasmaVault
|
|
25
23
|
from ipor_fusion.vault_data import fetch_vault_data
|
|
26
24
|
|
|
27
25
|
VAULT = Web3.to_checksum_address("0x45aa96f0b3188D47a1DaFdbefCE1db6B37f58216")
|
|
@@ -30,22 +28,9 @@ CHAIN_ID = 8453
|
|
|
30
28
|
BLOCK = 50788912
|
|
31
29
|
|
|
32
30
|
|
|
33
|
-
def _connect(url: str) -> tuple[Web3Context, PlasmaVault]:
|
|
34
|
-
"""Skip on infra problems only (unreachable or non-archive provider)."""
|
|
35
|
-
try:
|
|
36
|
-
ctx = Web3Context.from_url(url).at_block(BLOCK)
|
|
37
|
-
pv = PlasmaVault(VAULT)
|
|
38
|
-
pv.underlying_asset_address().call(ctx) # state read at BLOCK needs archive
|
|
39
|
-
except Exception as exc: # noqa: BLE001
|
|
40
|
-
pytest.skip(f"BASE on-chain read failed (provider missing/non-archive?): {exc}")
|
|
41
|
-
return ctx, pv
|
|
42
|
-
|
|
43
|
-
|
|
44
31
|
def test_vault_without_withdraw_manager_fetches_on_real_base_vault():
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
pytest.skip("BASE_PROVIDER_URL not set")
|
|
48
|
-
ctx, pv = _connect(url)
|
|
32
|
+
ctx = archive_context("BASE_PROVIDER_URL", BLOCK, VAULT)
|
|
33
|
+
pv = PlasmaVault(VAULT)
|
|
49
34
|
|
|
50
35
|
withdraw_manager = pv.read_withdraw_manager_address(ctx)
|
|
51
36
|
data = fetch_vault_data(ctx, pv.address, block=BLOCK)
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches:
|
|
6
|
-
- "**"
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
notify:
|
|
10
|
-
uses: ./.github/workflows/notify-slack.yml
|
|
11
|
-
secrets:
|
|
12
|
-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
|
13
|
-
|
|
14
|
-
build:
|
|
15
|
-
needs: notify
|
|
16
|
-
uses: ./.github/workflows/python-build.yml
|
|
17
|
-
secrets:
|
|
18
|
-
ETHEREUM_PROVIDER_URL: ${{ secrets.ETHEREUM_PROVIDER_URL }}
|
|
19
|
-
ARBITRUM_PROVIDER_URL: ${{ secrets.ARBITRUM_PROVIDER_URL }}
|
|
20
|
-
BASE_PROVIDER_URL: ${{ secrets.BASE_PROVIDER_URL }}
|
|
21
|
-
|
|
22
|
-
report:
|
|
23
|
-
if: ${{ always() }}
|
|
24
|
-
needs:
|
|
25
|
-
- notify
|
|
26
|
-
- build
|
|
27
|
-
uses: ./.github/workflows/report-slack.yml
|
|
28
|
-
secrets:
|
|
29
|
-
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
|
30
|
-
with:
|
|
31
|
-
success: ${{ needs.build.result == 'success' }}
|
|
32
|
-
slack-status-msg-id: ${{ needs.notify.outputs.slack-status-msg-id }}
|
|
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.dev200 → ipor_fusion-4.0.0.dev206}/examples/advanced_euler_v2_looping_arbitrum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/external_state_margin_leg_base.py
RENAMED
|
File without changes
|
{ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/examples/simple_aave_v3_supply_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
|
|
File without changes
|
{ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/oracle_mapping_view.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev200 → ipor_fusion-4.0.0.dev206}/src/ipor_fusion/cli/vault_info_view.py
RENAMED
|
File without changes
|