ipor-fusion 4.0.0.dev162__tar.gz → 4.0.0.dev168__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.dev162 → ipor_fusion-4.0.0.dev168}/AGENTS.md +10 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/MIGRATION_4.md +42 -9
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/advanced_euler_v2_credit_market_base.py +1 -3
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/advanced_euler_v2_looping_arbitrum.py +1 -3
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +1 -1
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +1 -1
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/external_state_margin_leg_base.py +1 -3
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/simple_aave_v3_supply_base.py +1 -3
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/__init__.py +54 -4
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/simulation.py +52 -19
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/__init__.py +34 -2
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/external_state_events.py +106 -35
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/hypercore_events.py +157 -36
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_event_args.py +14 -3
- ipor_fusion-4.0.0.dev168/tests/_golden.py +69 -0
- ipor_fusion-4.0.0.dev168/tests/_oracle_mapping_fake.py +200 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/meta_morpho_v1.json +99 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +111 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/meta_morpho_v2.json +135 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +140 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_api/market.json +208 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_api/vault_v1.json +168 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_api/vault_v2.json +115 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +12 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_blue.json +107 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_blue.mcp.json +108 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_blue_api_error.json +28 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +31 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_blue_no_api.json +27 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +31 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/oracle_mapping_golden/mapping.json +573 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +573 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/vault_info_golden/clean.mcp.json +136 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/vault_info_golden/deployment_error.json +131 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/vault_info_golden/deployment_error.mcp.json +138 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/vault_info_golden/deployment_error.txt +54 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/vault_info_golden/full.json +688 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/vault_info_golden/full.mcp.json +709 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/vault_info_golden/full.txt +154 -0
- ipor_fusion-4.0.0.dev168/tests/fixtures/vault_info_golden/rich.mcp.json +406 -0
- ipor_fusion-4.0.0.dev168/tests/test_cli_market_golden.py +199 -0
- ipor_fusion-4.0.0.dev168/tests/test_cli_oracle_mapping_golden.py +275 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_vault_info_golden.py +264 -16
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_external_state_events.py +8 -6
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_hypercore_events.py +21 -14
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_oracle_mapping.py +25 -193
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_public_api.py +44 -3
- ipor_fusion-4.0.0.dev168/tests/test_simulation_errors.py +229 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/typed_client/consumer.py +24 -6
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/typed_client/rejected.py +4 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/README.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/mcp/server.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/vault_data.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/fixtures/simulate_v1_request.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_simulation_observation.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_vault_data_block.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/uv.lock +0 -0
|
@@ -32,9 +32,19 @@ uv run pytest -m "cli or mcp" --no-cov # fast offline sub
|
|
|
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
|
|
35
|
+
UPDATE_GOLDEN=1 uv run pytest -k golden --no-cov # rewrite pinned CLI/MCP output (tests/fixtures/*_golden/)
|
|
35
36
|
uv lock --check # uv.lock in sync with pyproject.toml
|
|
36
37
|
```
|
|
37
38
|
|
|
39
|
+
**Golden output.** The exact text of `fusion vault info` (text and `--json`),
|
|
40
|
+
`fusion market morpho-blue|meta-morpho --json`, `fusion vault oracle-mapping
|
|
41
|
+
--json` and the matching MCP tools (`vault_info`, `market_morpho_blue`,
|
|
42
|
+
`market_meta_morpho`, `vault_oracle_mapping`, called through the server) is pinned
|
|
43
|
+
in `tests/fixtures/*_golden/` (`tests/_golden.py`, the `*_golden.py` tests), from
|
|
44
|
+
recorded inputs and no network. A change to any of them fails those tests;
|
|
45
|
+
regenerate with `UPDATE_GOLDEN=1` only when the change is intended and review the
|
|
46
|
+
fixture diff. Without it the tests only compare.
|
|
47
|
+
|
|
38
48
|
Run format, check, pyright and pytest after every code change; that is exactly
|
|
39
49
|
the sequence in `.github/workflows/python-build.yml`. When ruff `C901` trips,
|
|
40
50
|
extract helpers, never suppress.
|
|
@@ -847,15 +847,31 @@ that only some entries carry is `NotRequired` (a balance fuse's `pct_of_total` a
|
|
|
847
847
|
`ipor_fusion` and `ipor_fusion.readers`). Narrow by a key before reading a
|
|
848
848
|
kind-specific one: `if detail is not None and "aggregator" in detail:
|
|
849
849
|
detail["description"]`.
|
|
850
|
-
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
`
|
|
854
|
-
`
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
850
|
+
- Decoded events are discriminated unions. `ExternalStateEvent` and `HyperCoreEvent`
|
|
851
|
+
are type aliases over one frozen dataclass per event (`ExternalStateUnpausedEvent`,
|
|
852
|
+
`HyperCoreDepositFuseEnterEvent`, ...), each with `name: Literal["<event>"]` and
|
|
853
|
+
`args` typed as that event's TypedDict (`ExternalStateUnpausedArgs`, ...). Comparing
|
|
854
|
+
`name` narrows the event and its `args`, with no key test:
|
|
855
|
+
|
|
856
|
+
```python
|
|
857
|
+
for event in external_state_events(receipt):
|
|
858
|
+
if event.name == "ExternalStateUnpaused":
|
|
859
|
+
event.args["signer"] # ChecksumAddress
|
|
860
|
+
match hc_event:
|
|
861
|
+
case HyperCoreDepositFuseEnterEvent(args=args):
|
|
862
|
+
args["evmAsset"]
|
|
863
|
+
```
|
|
864
|
+
|
|
865
|
+
Without that comparison `event.args["signer"]` does not type-check.
|
|
866
|
+
`isinstance(x, ExternalStateEvent)` still works (the alias is a union); the events
|
|
867
|
+
are no longer built positionally (`ExternalStateEvent(...)` is not a class: build
|
|
868
|
+
the event's own class with keywords, its `name` is preset).
|
|
869
|
+
`EXTERNAL_STATE_EVENT_CLASSES` / `HYPERCORE_EVENT_CLASSES` map an event name to its
|
|
870
|
+
class; they replace `EXTERNAL_STATE_EVENT_ARGS` / `HYPERCORE_EVENT_ARGS`, which are
|
|
871
|
+
removed. An event's args TypedDict is its class's `args` annotation:
|
|
872
|
+
`typing.get_type_hints(EXTERNAL_STATE_EVENT_CLASSES[name])["args"]`. Values carry nominal types (`Amount`, `MarketId`, `FuseAddress`,
|
|
873
|
+
`HyperCoreTokenIndex`, `PayloadHash`, web3's `Timestamp`, ...), and
|
|
874
|
+
`HyperCoreEvent.fuse` is a `FuseAddress | None` on every event.
|
|
859
875
|
- `RawLog` (the log shape `ExternalStateExecutor.parse_balance_proposed` /
|
|
860
876
|
`find_balance_proposed` accept) is `Mapping[str, object]`, not `Mapping[str, Any]`;
|
|
861
877
|
a web3 `LogReceipt` still fits it.
|
|
@@ -935,5 +951,22 @@ are listed with a link.
|
|
|
935
951
|
decoder cannot read raises the decoder's error. 3.x left it out of
|
|
936
952
|
`result.observations` (so `result.get(label)` raised `KeyError`) or reported an
|
|
937
953
|
undecodable read as `None`, indistinguishable from a read that returns `None`.
|
|
954
|
+
- **Check `success`; `error` is always set on failure.** A failed
|
|
955
|
+
`SimulatedCallResult` always carries a non-empty `error`: the node's message joined
|
|
956
|
+
with the decoded revert (`"execution reverted: NotAllowed"`), the decoded revert
|
|
957
|
+
alone when the node sent no message, else `"reverted without a reason"` (with the
|
|
958
|
+
return data's hex when it is too short to decode). 3.x could report `success=False`
|
|
959
|
+
with `error=None`, and `error` was the node's message only. A successful call's
|
|
960
|
+
`error` is `None`, and constructing one with an `error` raises `ValueError`.
|
|
961
|
+
`revert_reason` is `None` exactly when the call succeeded. The messages of
|
|
962
|
+
`SimulationResult.raise_for_failure` and `SimulationObservation.value`'s
|
|
963
|
+
`SimulationError` are `failed: {error}`; drop any `call.error or "reverted"`
|
|
964
|
+
fallback and match on `revert_reason`, not on the text of `error`.
|
|
965
|
+
- **`SimulatedCallResult` and `SimulationResult` are frozen**, so the rule above
|
|
966
|
+
holds after construction too: assigning a field raises
|
|
967
|
+
`dataclasses.FrozenInstanceError`. Build a changed copy with
|
|
968
|
+
`dataclasses.replace(result, ...)` (a failed call's `error` is completed again).
|
|
969
|
+
Both stay unhashable (`__hash__` is `None`, as before). The freeze is shallow:
|
|
970
|
+
the `logs` / `calls` lists themselves can still be mutated.
|
|
938
971
|
- Saved config entries are checksummed when loaded; the MCP `vault_add` tool rejects
|
|
939
972
|
a value that is not an address.
|
|
@@ -191,9 +191,7 @@ def _assert_all_success(result: SimulationResult) -> None:
|
|
|
191
191
|
if result.all_success:
|
|
192
192
|
return
|
|
193
193
|
failed = [(c.label, c.error) for c in result.failed_calls]
|
|
194
|
-
raise AssertionError(
|
|
195
|
-
f"simulation calls failed: {failed} (reason={result.revert_reason})"
|
|
196
|
-
)
|
|
194
|
+
raise AssertionError(f"simulation calls failed: {failed}")
|
|
197
195
|
|
|
198
196
|
|
|
199
197
|
def _connected_web3() -> Web3:
|
{ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/advanced_euler_v2_looping_arbitrum.py
RENAMED
|
@@ -153,9 +153,7 @@ def _assert_all_success(result: SimulationResult) -> None:
|
|
|
153
153
|
if result.all_success:
|
|
154
154
|
return
|
|
155
155
|
failed = [(call.label, call.error) for call in result.failed_calls]
|
|
156
|
-
raise AssertionError(
|
|
157
|
-
f"simulation calls failed: {failed} (reason={result.revert_reason})"
|
|
158
|
-
)
|
|
156
|
+
raise AssertionError(f"simulation calls failed: {failed}")
|
|
159
157
|
|
|
160
158
|
|
|
161
159
|
def _connected_web3() -> Web3:
|
|
@@ -634,7 +634,7 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
|
|
|
634
634
|
# ── Part B: the hub legs, simulated at pinned blocks ─────────────────────────
|
|
635
635
|
def _assert_relay_success(results: dict[ChainId, SimulationResult]) -> None:
|
|
636
636
|
failed = [
|
|
637
|
-
f"{chain}:{call.label}:{call.
|
|
637
|
+
f"{chain}:{call.label}:{call.error}"
|
|
638
638
|
for chain, result in results.items()
|
|
639
639
|
for call in result.calls
|
|
640
640
|
if not call.success
|
|
@@ -179,7 +179,7 @@ def _assert_relay_success(results: dict[ChainId, SimulationResult]) -> None:
|
|
|
179
179
|
"""Raise with a readable summary if any simulated call on either chain
|
|
180
180
|
reverted; each entry names the call and decodes its own revert."""
|
|
181
181
|
failed = [
|
|
182
|
-
(int(chain_id), call.label, call.
|
|
182
|
+
(int(chain_id), call.label, call.error)
|
|
183
183
|
for chain_id, result in results.items()
|
|
184
184
|
for call in result.calls
|
|
185
185
|
if not call.success
|
{ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/external_state_margin_leg_base.py
RENAMED
|
@@ -332,9 +332,7 @@ def _assert_all_success(result: SimulationResult) -> None:
|
|
|
332
332
|
if result.all_success:
|
|
333
333
|
return
|
|
334
334
|
failed = [(c.label, c.error) for c in result.failed_calls]
|
|
335
|
-
raise AssertionError(
|
|
336
|
-
f"simulation calls failed: {failed} (reason={result.revert_reason})"
|
|
337
|
-
)
|
|
335
|
+
raise AssertionError(f"simulation calls failed: {failed}")
|
|
338
336
|
|
|
339
337
|
|
|
340
338
|
def _assert_only_expected_failure(result: SimulationResult, label: str) -> bytes:
|
{ipor_fusion-4.0.0.dev162 → ipor_fusion-4.0.0.dev168}/examples/simple_aave_v3_supply_base.py
RENAMED
|
@@ -159,9 +159,7 @@ def _assert_all_success(result: SimulationResult) -> None:
|
|
|
159
159
|
if result.all_success:
|
|
160
160
|
return
|
|
161
161
|
failed = [(c.label, c.error) for c in result.failed_calls]
|
|
162
|
-
raise AssertionError(
|
|
163
|
-
f"simulation calls failed: {failed} (reason={result.revert_reason})"
|
|
164
|
-
)
|
|
162
|
+
raise AssertionError(f"simulation calls failed: {failed}")
|
|
165
163
|
|
|
166
164
|
|
|
167
165
|
def _connected_web3() -> Web3:
|
|
@@ -316,43 +316,68 @@ from ipor_fusion.fuses import (
|
|
|
316
316
|
system_address,
|
|
317
317
|
)
|
|
318
318
|
from ipor_fusion.fuses.external_state_events import (
|
|
319
|
-
|
|
319
|
+
EXTERNAL_STATE_EVENT_CLASSES,
|
|
320
320
|
EXTERNAL_STATE_EVENT_SPECS,
|
|
321
321
|
EXTERNAL_STATE_EVENTS,
|
|
322
322
|
EXTERNAL_STATE_TOPICS,
|
|
323
323
|
ExternalStateAssetRescuedArgs,
|
|
324
|
+
ExternalStateAssetRescuedEvent,
|
|
325
|
+
ExternalStateBalanceFuseLastCustodianTimestampUpdatedEvent,
|
|
326
|
+
ExternalStateBalanceFuseLastTotalBalanceUpdatedEvent,
|
|
324
327
|
ExternalStateBigChangeDetectedArgs,
|
|
328
|
+
ExternalStateBigChangeDetectedEvent,
|
|
325
329
|
ExternalStateCustodianTimestampUpdatedArgs,
|
|
326
330
|
ExternalStateEvent,
|
|
327
331
|
ExternalStateEventArgs,
|
|
328
332
|
ExternalStateEventSpec,
|
|
329
333
|
ExternalStateExecutorArgs,
|
|
334
|
+
ExternalStateExecutorCreatedEvent,
|
|
335
|
+
ExternalStateExecutorDeployedEvent,
|
|
330
336
|
ExternalStateOperationArgs,
|
|
337
|
+
ExternalStateOperationFuseEnterEvent,
|
|
338
|
+
ExternalStateOperationFuseExitEvent,
|
|
331
339
|
ExternalStateTotalBalanceUpdatedArgs,
|
|
332
340
|
ExternalStateUnpausedArgs,
|
|
341
|
+
ExternalStateUnpausedEvent,
|
|
333
342
|
decode_external_state_event,
|
|
334
343
|
external_state_event_name,
|
|
335
344
|
external_state_events,
|
|
336
345
|
)
|
|
337
346
|
from ipor_fusion.fuses.hypercore_events import (
|
|
338
|
-
|
|
347
|
+
HYPERCORE_EVENT_CLASSES,
|
|
339
348
|
HyperCoreActionEnqueuedArgs,
|
|
349
|
+
HyperCoreActionEnqueuedEvent,
|
|
340
350
|
HyperCoreActionSettledArgs,
|
|
351
|
+
HyperCoreActionSettledEvent,
|
|
341
352
|
HyperCoreBuilderFeeFuseEnterArgs,
|
|
353
|
+
HyperCoreBuilderFeeFuseEnterEvent,
|
|
342
354
|
HyperCoreCancelByCloidArgs,
|
|
343
355
|
HyperCoreCancelByOidArgs,
|
|
356
|
+
HyperCoreCancelFuseCancelByCloidEvent,
|
|
357
|
+
HyperCoreCancelFuseCancelByOidEvent,
|
|
344
358
|
HyperCoreDepositFuseEnterArgs,
|
|
359
|
+
HyperCoreDepositFuseEnterEvent,
|
|
345
360
|
HyperCoreEventArgs,
|
|
346
361
|
HyperCoreMarginFuseEnterArgs,
|
|
362
|
+
HyperCoreMarginFuseEnterEvent,
|
|
347
363
|
HyperCoreObserverSetChangedArgs,
|
|
364
|
+
HyperCoreObserverSetChangedEvent,
|
|
348
365
|
HyperCoreObserverSetProposedArgs,
|
|
366
|
+
HyperCoreObserverSetProposedEvent,
|
|
349
367
|
HyperCoreOrderFuseEnterArgs,
|
|
368
|
+
HyperCoreOrderFuseEnterEvent,
|
|
350
369
|
HyperCoreRecoveryExecutedArgs,
|
|
370
|
+
HyperCoreRecoveryExecutedEvent,
|
|
351
371
|
HyperCoreRecoveryProposedArgs,
|
|
372
|
+
HyperCoreRecoveryProposedEvent,
|
|
352
373
|
HyperCoreReportedActionSettledArgs,
|
|
374
|
+
HyperCoreReportedActionSettledEvent,
|
|
353
375
|
HyperCoreReportSubmittedArgs,
|
|
376
|
+
HyperCoreReportSubmittedEvent,
|
|
354
377
|
HyperCoreSendFuseSendAssetArgs,
|
|
378
|
+
HyperCoreSendFuseSendAssetEvent,
|
|
355
379
|
HyperCoreSendFuseSpotSendArgs,
|
|
380
|
+
HyperCoreSendFuseSpotSendEvent,
|
|
356
381
|
)
|
|
357
382
|
from ipor_fusion.market_ids import IporFusionMarkets
|
|
358
383
|
from ipor_fusion.market_info import (
|
|
@@ -591,7 +616,16 @@ __all__ = [
|
|
|
591
616
|
"EXTERNAL_STATE_EVENTS",
|
|
592
617
|
"EXTERNAL_STATE_TOPICS",
|
|
593
618
|
"ExternalStateEvent",
|
|
594
|
-
"
|
|
619
|
+
"EXTERNAL_STATE_EVENT_CLASSES",
|
|
620
|
+
"ExternalStateBigChangeDetectedEvent",
|
|
621
|
+
"ExternalStateBalanceFuseLastCustodianTimestampUpdatedEvent",
|
|
622
|
+
"ExternalStateBalanceFuseLastTotalBalanceUpdatedEvent",
|
|
623
|
+
"ExternalStateUnpausedEvent",
|
|
624
|
+
"ExternalStateAssetRescuedEvent",
|
|
625
|
+
"ExternalStateExecutorCreatedEvent",
|
|
626
|
+
"ExternalStateOperationFuseEnterEvent",
|
|
627
|
+
"ExternalStateOperationFuseExitEvent",
|
|
628
|
+
"ExternalStateExecutorDeployedEvent",
|
|
595
629
|
"ExternalStateAssetRescuedArgs",
|
|
596
630
|
"ExternalStateBigChangeDetectedArgs",
|
|
597
631
|
"ExternalStateCustodianTimestampUpdatedArgs",
|
|
@@ -608,7 +642,23 @@ __all__ = [
|
|
|
608
642
|
"HYPERCORE_EVENTS",
|
|
609
643
|
"HYPERCORE_EVENT_SPECS",
|
|
610
644
|
"HyperCoreEvent",
|
|
611
|
-
"
|
|
645
|
+
"HYPERCORE_EVENT_CLASSES",
|
|
646
|
+
"HyperCoreDepositFuseEnterEvent",
|
|
647
|
+
"HyperCoreMarginFuseEnterEvent",
|
|
648
|
+
"HyperCoreSendFuseSpotSendEvent",
|
|
649
|
+
"HyperCoreSendFuseSendAssetEvent",
|
|
650
|
+
"HyperCoreOrderFuseEnterEvent",
|
|
651
|
+
"HyperCoreCancelFuseCancelByOidEvent",
|
|
652
|
+
"HyperCoreCancelFuseCancelByCloidEvent",
|
|
653
|
+
"HyperCoreBuilderFeeFuseEnterEvent",
|
|
654
|
+
"HyperCoreActionEnqueuedEvent",
|
|
655
|
+
"HyperCoreActionSettledEvent",
|
|
656
|
+
"HyperCoreReportedActionSettledEvent",
|
|
657
|
+
"HyperCoreReportSubmittedEvent",
|
|
658
|
+
"HyperCoreObserverSetProposedEvent",
|
|
659
|
+
"HyperCoreObserverSetChangedEvent",
|
|
660
|
+
"HyperCoreRecoveryProposedEvent",
|
|
661
|
+
"HyperCoreRecoveryExecutedEvent",
|
|
612
662
|
"HyperCoreActionEnqueuedArgs",
|
|
613
663
|
"HyperCoreActionSettledArgs",
|
|
614
664
|
"HyperCoreBuilderFeeFuseEnterArgs",
|
|
@@ -142,8 +142,17 @@ class _Block:
|
|
|
142
142
|
override_provider: StateOverrideProvider | None = None
|
|
143
143
|
|
|
144
144
|
|
|
145
|
-
@dataclass(slots=True)
|
|
145
|
+
@dataclass(frozen=True, slots=True)
|
|
146
146
|
class SimulatedCallResult:
|
|
147
|
+
"""One simulated call. ``error`` is set exactly when ``success`` is False:
|
|
148
|
+
check ``success``, then read ``error`` for a non-empty, human-readable
|
|
149
|
+
failure (the node's message with the decoded revert reason, or
|
|
150
|
+
``"reverted without a reason"`` plus any undecodable return data).
|
|
151
|
+
Construction enforces it: a failed call's ``error`` is completed from its
|
|
152
|
+
return data, and a successful call given an ``error`` raises
|
|
153
|
+
``ValueError``. The record is frozen, so the invariant holds afterwards;
|
|
154
|
+
build a changed copy with `dataclasses.replace`."""
|
|
155
|
+
|
|
147
156
|
label: str | None
|
|
148
157
|
success: bool
|
|
149
158
|
return_data: HexBytes
|
|
@@ -151,19 +160,33 @@ class SimulatedCallResult:
|
|
|
151
160
|
error: str | None
|
|
152
161
|
logs: list[dict]
|
|
153
162
|
predicted_address: ChecksumAddress | None = None
|
|
163
|
+
# Frozen would add a __hash__ that fails on the logs list; stay unhashable.
|
|
164
|
+
__hash__ = None # type: ignore[assignment]
|
|
165
|
+
|
|
166
|
+
def __post_init__(self) -> None:
|
|
167
|
+
if self.success:
|
|
168
|
+
if self.error is not None:
|
|
169
|
+
raise ValueError(
|
|
170
|
+
f"successful simulated call {self.label!r} carries an error"
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
# The record is frozen; completing the error is part of building it.
|
|
174
|
+
object.__setattr__(
|
|
175
|
+
self, "error", _failure_message(self.error, self.return_data)
|
|
176
|
+
)
|
|
154
177
|
|
|
155
178
|
@property
|
|
156
179
|
def revert_reason(self) -> str | None:
|
|
157
180
|
"""This call's decoded revert (a registered custom error by name, an
|
|
158
|
-
``Error(string)`` text or ``Panic``), ``None``
|
|
159
|
-
|
|
181
|
+
``Error(string)`` text or ``Panic``), else its ``error``; ``None``
|
|
182
|
+
exactly when it succeeded. ``SimulationResult.revert_reason`` is the
|
|
160
183
|
chain's first failed call, which may be a different one."""
|
|
161
184
|
if self.success:
|
|
162
185
|
return None
|
|
163
186
|
return _decode_revert(self.return_data, self.error)
|
|
164
187
|
|
|
165
188
|
|
|
166
|
-
@dataclass(slots=True)
|
|
189
|
+
@dataclass(frozen=True, slots=True)
|
|
167
190
|
class SimulationResult:
|
|
168
191
|
success: bool
|
|
169
192
|
all_success: bool
|
|
@@ -172,6 +195,7 @@ class SimulationResult:
|
|
|
172
195
|
execute_logs: list[dict]
|
|
173
196
|
calls: list[SimulatedCallResult] = field(default_factory=list)
|
|
174
197
|
failed_calls: list[SimulatedCallResult] = field(default_factory=list)
|
|
198
|
+
__hash__ = None # type: ignore[assignment]
|
|
175
199
|
|
|
176
200
|
def raise_for_failure(self) -> None:
|
|
177
201
|
"""Raise :class:`SimulationError` naming the first failed call (label,
|
|
@@ -179,15 +203,11 @@ class SimulationResult:
|
|
|
179
203
|
if not self.failed_calls:
|
|
180
204
|
return
|
|
181
205
|
first = self.failed_calls[0]
|
|
182
|
-
reason = _decode_revert(first.return_data, first.error)
|
|
183
206
|
label = first.label or "<unlabelled>"
|
|
184
|
-
detail = first.error or "reverted"
|
|
185
|
-
if reason and reason != first.error:
|
|
186
|
-
detail = f"{detail}: {reason}"
|
|
187
207
|
raise SimulationError(
|
|
188
|
-
f"simulated call {label!r} failed: {
|
|
208
|
+
f"simulated call {label!r} failed: {first.error}",
|
|
189
209
|
label=first.label,
|
|
190
|
-
revert_reason=
|
|
210
|
+
revert_reason=first.revert_reason,
|
|
191
211
|
)
|
|
192
212
|
|
|
193
213
|
|
|
@@ -223,12 +243,10 @@ class SimulationObservation(Generic[T_co]):
|
|
|
223
243
|
result = self.result
|
|
224
244
|
name = self._label or "<unlabelled>"
|
|
225
245
|
if not result.success:
|
|
226
|
-
reason = result.revert_reason
|
|
227
246
|
raise SimulationError(
|
|
228
|
-
f"observation {name!r} failed: {result.error
|
|
229
|
-
+ (f": {reason}" if reason and reason != result.error else ""),
|
|
247
|
+
f"observation {name!r} failed: {result.error}",
|
|
230
248
|
label=self._label,
|
|
231
|
-
revert_reason=
|
|
249
|
+
revert_reason=result.revert_reason,
|
|
232
250
|
)
|
|
233
251
|
if not result.return_data:
|
|
234
252
|
raise EmptyCallResultError(
|
|
@@ -732,7 +750,7 @@ class VaultSimulator:
|
|
|
732
750
|
status = int(raw.get("status", "0x1"), 16)
|
|
733
751
|
success = status == 1
|
|
734
752
|
gas_used = int(raw.get("gasUsed", "0x0"), 16)
|
|
735
|
-
|
|
753
|
+
message, return_data = _normalize_call_error(raw.get("error"), return_data)
|
|
736
754
|
logs = raw.get("logs", []) or []
|
|
737
755
|
|
|
738
756
|
call_result = SimulatedCallResult(
|
|
@@ -740,7 +758,7 @@ class VaultSimulator:
|
|
|
740
758
|
success=success,
|
|
741
759
|
return_data=return_data,
|
|
742
760
|
gas_used=gas_used,
|
|
743
|
-
error=
|
|
761
|
+
error=None if success else message,
|
|
744
762
|
logs=logs,
|
|
745
763
|
predicted_address=(source.predicted_address if success else None),
|
|
746
764
|
)
|
|
@@ -753,14 +771,13 @@ class VaultSimulator:
|
|
|
753
771
|
execute_gas += gas_used
|
|
754
772
|
execute_logs.extend(logs)
|
|
755
773
|
if not success and revert_reason is None:
|
|
756
|
-
revert_reason =
|
|
774
|
+
revert_reason = call_result.revert_reason
|
|
757
775
|
|
|
758
776
|
failed_calls = [c for c in parsed if not c.success]
|
|
759
777
|
all_success = not failed_calls
|
|
760
778
|
if revert_reason is None and failed_calls:
|
|
761
779
|
# No execute call reverted but a setup/observation did — surface it.
|
|
762
|
-
|
|
763
|
-
revert_reason = _decode_revert(first_failed.return_data, first_failed.error)
|
|
780
|
+
revert_reason = failed_calls[0].revert_reason
|
|
764
781
|
|
|
765
782
|
return SimulationResult(
|
|
766
783
|
success=execute_success,
|
|
@@ -910,6 +927,22 @@ def _normalize_call_error(
|
|
|
910
927
|
return (error_raw if isinstance(error_raw, str) else None), return_data
|
|
911
928
|
|
|
912
929
|
|
|
930
|
+
def _failure_message(message: str | None, return_data: HexBytes) -> str:
|
|
931
|
+
"""A failed call's ``error``: the node's message joined with the decoded
|
|
932
|
+
revert unless the message already carries it, else whichever exists, else
|
|
933
|
+
``"reverted without a reason"`` with any return data too short to decode."""
|
|
934
|
+
reason = _decode_revert(return_data, None)
|
|
935
|
+
if message and reason:
|
|
936
|
+
return message if reason in message else f"{message}: {reason}"
|
|
937
|
+
if message:
|
|
938
|
+
return message
|
|
939
|
+
if reason:
|
|
940
|
+
return reason
|
|
941
|
+
if return_data:
|
|
942
|
+
return f"reverted without a reason (return data 0x{bytes(return_data).hex()})"
|
|
943
|
+
return "reverted without a reason"
|
|
944
|
+
|
|
945
|
+
|
|
913
946
|
def _decode_revert(return_data: HexBytes, error: str | None) -> str | None:
|
|
914
947
|
if return_data and len(return_data) >= 4:
|
|
915
948
|
selector = bytes(return_data[:4])
|
|
@@ -50,28 +50,44 @@ from ipor_fusion.fuses.hypercore import (
|
|
|
50
50
|
system_address,
|
|
51
51
|
)
|
|
52
52
|
from ipor_fusion.fuses.hypercore_events import (
|
|
53
|
-
|
|
53
|
+
HYPERCORE_EVENT_CLASSES,
|
|
54
54
|
HYPERCORE_EVENT_SPECS,
|
|
55
55
|
HYPERCORE_EVENTS,
|
|
56
56
|
HyperCoreActionEnqueuedArgs,
|
|
57
|
+
HyperCoreActionEnqueuedEvent,
|
|
57
58
|
HyperCoreActionSettledArgs,
|
|
59
|
+
HyperCoreActionSettledEvent,
|
|
58
60
|
HyperCoreBuilderFeeFuseEnterArgs,
|
|
61
|
+
HyperCoreBuilderFeeFuseEnterEvent,
|
|
59
62
|
HyperCoreCancelByCloidArgs,
|
|
60
63
|
HyperCoreCancelByOidArgs,
|
|
64
|
+
HyperCoreCancelFuseCancelByCloidEvent,
|
|
65
|
+
HyperCoreCancelFuseCancelByOidEvent,
|
|
61
66
|
HyperCoreDepositFuseEnterArgs,
|
|
67
|
+
HyperCoreDepositFuseEnterEvent,
|
|
62
68
|
HyperCoreEvent,
|
|
63
69
|
HyperCoreEventArgs,
|
|
64
70
|
HyperCoreEventSpec,
|
|
65
71
|
HyperCoreMarginFuseEnterArgs,
|
|
72
|
+
HyperCoreMarginFuseEnterEvent,
|
|
66
73
|
HyperCoreObserverSetChangedArgs,
|
|
74
|
+
HyperCoreObserverSetChangedEvent,
|
|
67
75
|
HyperCoreObserverSetProposedArgs,
|
|
76
|
+
HyperCoreObserverSetProposedEvent,
|
|
68
77
|
HyperCoreOrderFuseEnterArgs,
|
|
78
|
+
HyperCoreOrderFuseEnterEvent,
|
|
69
79
|
HyperCoreRecoveryExecutedArgs,
|
|
80
|
+
HyperCoreRecoveryExecutedEvent,
|
|
70
81
|
HyperCoreRecoveryProposedArgs,
|
|
82
|
+
HyperCoreRecoveryProposedEvent,
|
|
71
83
|
HyperCoreReportedActionSettledArgs,
|
|
84
|
+
HyperCoreReportedActionSettledEvent,
|
|
72
85
|
HyperCoreReportSubmittedArgs,
|
|
86
|
+
HyperCoreReportSubmittedEvent,
|
|
73
87
|
HyperCoreSendFuseSendAssetArgs,
|
|
88
|
+
HyperCoreSendFuseSendAssetEvent,
|
|
74
89
|
HyperCoreSendFuseSpotSendArgs,
|
|
90
|
+
HyperCoreSendFuseSpotSendEvent,
|
|
75
91
|
decode_hypercore_event,
|
|
76
92
|
find_hypercore_events,
|
|
77
93
|
hypercore_event_name,
|
|
@@ -112,7 +128,23 @@ __all__ = [
|
|
|
112
128
|
"HYPERCORE_EVENTS",
|
|
113
129
|
"HYPERCORE_EVENT_SPECS",
|
|
114
130
|
"HyperCoreEvent",
|
|
115
|
-
"
|
|
131
|
+
"HYPERCORE_EVENT_CLASSES",
|
|
132
|
+
"HyperCoreDepositFuseEnterEvent",
|
|
133
|
+
"HyperCoreMarginFuseEnterEvent",
|
|
134
|
+
"HyperCoreSendFuseSpotSendEvent",
|
|
135
|
+
"HyperCoreSendFuseSendAssetEvent",
|
|
136
|
+
"HyperCoreOrderFuseEnterEvent",
|
|
137
|
+
"HyperCoreCancelFuseCancelByOidEvent",
|
|
138
|
+
"HyperCoreCancelFuseCancelByCloidEvent",
|
|
139
|
+
"HyperCoreBuilderFeeFuseEnterEvent",
|
|
140
|
+
"HyperCoreActionEnqueuedEvent",
|
|
141
|
+
"HyperCoreActionSettledEvent",
|
|
142
|
+
"HyperCoreReportedActionSettledEvent",
|
|
143
|
+
"HyperCoreReportSubmittedEvent",
|
|
144
|
+
"HyperCoreObserverSetProposedEvent",
|
|
145
|
+
"HyperCoreObserverSetChangedEvent",
|
|
146
|
+
"HyperCoreRecoveryProposedEvent",
|
|
147
|
+
"HyperCoreRecoveryExecutedEvent",
|
|
116
148
|
"HyperCoreActionEnqueuedArgs",
|
|
117
149
|
"HyperCoreActionSettledArgs",
|
|
118
150
|
"HyperCoreBuilderFeeFuseEnterArgs",
|