ipor-fusion 4.1.0.dev54__tar.gz → 4.1.1.dev2__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.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.claude-plugin/plugin.json +1 -1
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/CHANGELOG.md +126 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/PKG-INFO +1 -1
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/pyproject.toml +1 -1
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/context.py +4 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/erc20.py +7 -2
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/plasma_vault.py +4 -1
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/simulation_result.py +2 -1
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/errors.py +5 -2
- ipor_fusion-4.1.1.dev2/src/ipor_fusion/onchain_text.py +30 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/oracle_mapping_reader.py +4 -1
- ipor_fusion-4.1.1.dev2/tests/test_ccip_read_disabled.py +96 -0
- ipor_fusion-4.1.1.dev2/tests/test_onchain_text.py +62 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/uv.lock +1 -1
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.env.example +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.gemini/settings.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.gitignore +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/.python-version +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/AGENTS.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/CLAUDE.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/CODEOWNERS +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/LICENSE +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/MIGRATION_4.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/README.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/build.sh +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/README.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/hypercore_vault_official_deployment_hyperevm.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/pytest.ini +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/scripts/fusion_error_signatures.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/address_cmd.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/preflight_cmd.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/context_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/fuse_decoding.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/hypercore_pre_hooks.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/fusion_errors.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/hypercore/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/mcp/server.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/preflight.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/euler_v2.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/registry.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/vault_data.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_addresses.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_event_args.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_fake_rpc.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_foundry.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_golden.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_guide.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_live.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_multicall.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_oracle_mapping_fake.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_simulate.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/_validation.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/addresses.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/conftest.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/constants.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/hypercore_official.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_blue.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/simulate_v1_request.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/fetched.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/full.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/full.txt +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_about.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_addresses_helper.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cache.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_chains.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_address.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_market_golden.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_mcp_parity.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_oracle_mapping_golden.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_preflight.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_examples_hypercore_hyperevm.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_fuse_decoding.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_fusion_errors.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_governance_wrappers.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_guide.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_hypercore_pre_hooks.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_logs.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_mcp_address.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_mcp_preflight.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_preflight.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_public_api.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_registry.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_roles.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_examples_hyperevm.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_preflight_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_timelock_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulation_errors.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_simulation_observation.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_validation.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_vault_data_block.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_vault_info_fetched_golden.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_vault_reconciliation_onchain_base.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/tests/typed_client/rejected.py +0 -0
|
@@ -2,6 +2,132 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- version list -->
|
|
4
4
|
|
|
5
|
+
## v4.1.0 (2026-11-03)
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- **cli**: Accept a 0X prefix in address arguments
|
|
10
|
+
([`cc23ff7`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/cc23ff7be50ca760eb6adc1a245746bc93a62553))
|
|
11
|
+
|
|
12
|
+
- **cli**: Check address arguments with parse_checksum_address
|
|
13
|
+
([`4023d07`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/4023d0789ed78d1ab76ce8f44d76a98b65c366f6))
|
|
14
|
+
|
|
15
|
+
- **cli**: Print a set-provider hint that runs as shown
|
|
16
|
+
([`6dd2894`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/6dd2894693038bae57b256293a4128160f35fc02))
|
|
17
|
+
|
|
18
|
+
- **cli**: Read --block-number 0 as the latest block
|
|
19
|
+
([`8dd339f`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/8dd339f0d8412389c6a473a57f119e79473e9ef6))
|
|
20
|
+
|
|
21
|
+
- **mcp**: Name the preflight sender in its parse errors
|
|
22
|
+
([`b1a6115`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/b1a61158a1f25eb9516f0e96d1a5c794ff943c65))
|
|
23
|
+
|
|
24
|
+
- **mcp**: Read block_number=0 as the latest block
|
|
25
|
+
([`320bb93`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/320bb935726d83fd7787cab9bb82430681ee6a11))
|
|
26
|
+
|
|
27
|
+
- **mcp**: Reject a wrong EIP-55 checksum in the MetaMorpho vault
|
|
28
|
+
([`02a5159`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/02a5159d727f768a40e97aad6869ff3b0356c418))
|
|
29
|
+
|
|
30
|
+
- **mcp**: Reject a wrong EIP-55 checksum in the preflight sender
|
|
31
|
+
([`4d5af23`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/4d5af236721c2cd3e9e8a0f52ed045b06039b4fa))
|
|
32
|
+
|
|
33
|
+
- **mcp**: Reject a wrong EIP-55 checksum in vault arguments
|
|
34
|
+
([`37625ec`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/37625ecb172a3478fc7fb5e522027c71c0a98dcf))
|
|
35
|
+
|
|
36
|
+
- **sdk**: Check EIP-55 in every FusionInstance address field
|
|
37
|
+
([`951f49a`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/951f49a4ccceecef4a06b8c600c12564da0c6ce5))
|
|
38
|
+
|
|
39
|
+
- **sdk**: Do not follow CCIP-Read lookups from contracts
|
|
40
|
+
([`51c8ef2`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/51c8ef25e19b9e33c8ea4317a9e1df26ad87dccd))
|
|
41
|
+
|
|
42
|
+
- **sdk**: Read the latest block's number and timestamp in one call
|
|
43
|
+
([`60a4a8f`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/60a4a8f545714f1013a2f30145837b2d8ad421cb))
|
|
44
|
+
|
|
45
|
+
- **sdk**: Reject a 0X-prefixed zero address
|
|
46
|
+
([`556ee32`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/556ee329d7954ac39f2b0dff607fa2aba7ba3bdd))
|
|
47
|
+
|
|
48
|
+
- **sdk**: Reject a wrong EIP-55 checksum in the address parsers
|
|
49
|
+
([`deac726`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/deac7262bb5ccfdc0932eab8d22ed02bd66d4c3b))
|
|
50
|
+
|
|
51
|
+
- **sdk**: Report Euler V2 lending health and never drop a borrow market
|
|
52
|
+
([`1de4598`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/1de4598248b2a73d322d68359baaa74421244b2e))
|
|
53
|
+
|
|
54
|
+
- **sdk**: Stop reporting a rounding gap as a stale ERC20 cache
|
|
55
|
+
([`29ffb53`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/29ffb53377cd91308815a0d3ede18acfe640ee4a))
|
|
56
|
+
|
|
57
|
+
- **sdk**: Stop the oracle mapping at a price oracle manager delegation cycle
|
|
58
|
+
([`1470d93`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/1470d93f85f477e24a85e6a28013f4456149d128))
|
|
59
|
+
|
|
60
|
+
### Build System
|
|
61
|
+
|
|
62
|
+
- Bump aiohttp, multidict and mcp in the lock
|
|
63
|
+
([`3c266b1`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/3c266b195f3b6ae4b72bdf8e7ae5a2c165838cc1))
|
|
64
|
+
|
|
65
|
+
### Documentation
|
|
66
|
+
|
|
67
|
+
- Block 0 reads the latest block in the tools and the CLI
|
|
68
|
+
([`308ccd2`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/308ccd22cff554c3f31f1414a8e825fac8b00625))
|
|
69
|
+
|
|
70
|
+
- Keep the CCIP example's command gas inside HyperEVM's small block
|
|
71
|
+
([`5e3a093`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/5e3a093b66c79c9565f89b7c91615cb95c2e1ff7))
|
|
72
|
+
|
|
73
|
+
- **examples**: Build address literals with parse_checksum_address
|
|
74
|
+
([`c449d13`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/c449d13ab481ec9b13497bb435569d9651f5b38c))
|
|
75
|
+
|
|
76
|
+
- **sdk**: Say the HyperCore pre-hooks take no pre-hook substrates
|
|
77
|
+
([`b609593`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/b609593ebb4b05bfd2b866e6139f02321323f6a3))
|
|
78
|
+
|
|
79
|
+
- **sdk**: Wire the HyperCore example's pre-hooks with the helper
|
|
80
|
+
([`edd2776`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/edd277677da59872f5074d8dcba2b6b5cad2daa2))
|
|
81
|
+
|
|
82
|
+
### Features
|
|
83
|
+
|
|
84
|
+
- **sdk**: Add parse_checksum_address
|
|
85
|
+
([`a9a6b84`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/a9a6b848e606318fc76fa82dc2c54c7d5b4a94d9))
|
|
86
|
+
|
|
87
|
+
- **sdk**: Expose the HyperCore order and price scales
|
|
88
|
+
([`b75c645`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/b75c645f95c525114e181519fe75c2348b7962b7))
|
|
89
|
+
|
|
90
|
+
- **sdk**: HyperCore pre-hook wiring
|
|
91
|
+
([`6f16ae6`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/6f16ae6cbe2d0f3298308f4592538cb06e52eab6))
|
|
92
|
+
|
|
93
|
+
- **sdk**: Read the HyperCore best bid and ask
|
|
94
|
+
([`5fda9ee`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/5fda9ee754eb8085df3f8c432ce65565c045bddf))
|
|
95
|
+
|
|
96
|
+
- **sdk**: Report the feeds behind a Morpho oracle in the oracle mapping
|
|
97
|
+
([`c692d72`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/c692d72449805ee98ae786f14d41d28e6de2c24e))
|
|
98
|
+
|
|
99
|
+
- **sdk**: Support TAC (239) in the vault tooling again
|
|
100
|
+
([`0cc00c3`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/0cc00c3e8d30f5937296ec6dc40896a4e1c766f7))
|
|
101
|
+
|
|
102
|
+
### Refactoring
|
|
103
|
+
|
|
104
|
+
- **mcp**: Share _vault_arg's input normalization
|
|
105
|
+
([`80744af`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/80744afd6d52d33ba7e8a075478083aef4048384))
|
|
106
|
+
|
|
107
|
+
- **sdk**: Decode Euler V2 and Dolomite substrates into typed values
|
|
108
|
+
([`8f4f1ad`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/8f4f1ad5045772da897a3e31d8514b32c6386610))
|
|
109
|
+
|
|
110
|
+
- **sdk**: Make HyperCorePreHookWiring.selectors a class constant
|
|
111
|
+
([`ae9bf3e`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/ae9bf3e72f31fe795ef5683cd7287b40a1c83d14))
|
|
112
|
+
|
|
113
|
+
- **sdk**: Move the HyperCore pre-hook wiring to its own module
|
|
114
|
+
([`b150389`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/b1503891468fe4f54379d8ba49ce68d6b3c7e041))
|
|
115
|
+
|
|
116
|
+
- **sdk**: Name the 0x813 precompile POSITION2_PRECOMPILE
|
|
117
|
+
([`9529f22`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/9529f22e8a1517ef096fe1b4bff56dcaa8139e5a))
|
|
118
|
+
|
|
119
|
+
- **sdk**: Stop coercing HyperCorePreHookWiring's hooks
|
|
120
|
+
([`759448d`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/759448d02b3d690a5de636ee91363263e7dd0e40))
|
|
121
|
+
|
|
122
|
+
### Testing
|
|
123
|
+
|
|
124
|
+
- Share a miscased-address helper
|
|
125
|
+
([`5f769ac`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/5f769ac98160baa0fe2099b3255b0f91d2b4b223))
|
|
126
|
+
|
|
127
|
+
- **sdk**: Probe the core modules' CLI isolation in one subprocess
|
|
128
|
+
([`3fc160a`](https://github.com/IPOR-Labs/ipor-fusion.py/commit/3fc160a5766171dc7bb471968d2740521b59d69e))
|
|
129
|
+
|
|
130
|
+
|
|
5
131
|
## v4.0.0 (2026-10-23)
|
|
6
132
|
|
|
7
133
|
### Bug Fixes
|
|
@@ -100,6 +100,10 @@ class Web3Context:
|
|
|
100
100
|
log_source: LogSource | None = None,
|
|
101
101
|
cache: ContractCache | None = None,
|
|
102
102
|
):
|
|
103
|
+
# EIP-3668: web3 would otherwise follow a contract's OffchainLookup
|
|
104
|
+
# revert from inside eth.call, sending an HTTP request to a URL chosen
|
|
105
|
+
# by whoever deployed the contract. Nothing in the SDK reads through it.
|
|
106
|
+
web3.provider.global_ccip_read_enabled = False
|
|
103
107
|
self._web3 = web3
|
|
104
108
|
self._chain_id = chain_id
|
|
105
109
|
# Bounds of every `get_logs` scan: wall clock, and eth_getLogs requests
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from eth_typing import ChecksumAddress
|
|
2
2
|
|
|
3
3
|
from ipor_fusion.core.contract import Call, ContractWrapper
|
|
4
|
+
from ipor_fusion.onchain_text import sanitize_onchain_text
|
|
4
5
|
from ipor_fusion.types import Amount, Decimals
|
|
5
6
|
|
|
6
7
|
|
|
@@ -26,10 +27,14 @@ class ERC20(ContractWrapper):
|
|
|
26
27
|
return self._view("decimals()", output_types=["uint256"], decoder=Decimals)
|
|
27
28
|
|
|
28
29
|
def symbol(self) -> Call[str]:
|
|
29
|
-
return self._view(
|
|
30
|
+
return self._view(
|
|
31
|
+
"symbol()", output_types=["string"], decoder=sanitize_onchain_text
|
|
32
|
+
)
|
|
30
33
|
|
|
31
34
|
def name(self) -> Call[str]:
|
|
32
|
-
return self._view(
|
|
35
|
+
return self._view(
|
|
36
|
+
"name()", output_types=["string"], decoder=sanitize_onchain_text
|
|
37
|
+
)
|
|
33
38
|
|
|
34
39
|
def total_supply(self) -> Call[Amount]:
|
|
35
40
|
return self._view("totalSupply()", output_types=["uint256"], decoder=Amount)
|
|
@@ -18,6 +18,7 @@ from ipor_fusion.core.context import Web3Context
|
|
|
18
18
|
from ipor_fusion.core.contract import Call, ContractWrapper
|
|
19
19
|
from ipor_fusion.core.fuse_action import FuseAction
|
|
20
20
|
from ipor_fusion.errors import EmptyCallResultError, UnsupportedVaultVersionError
|
|
21
|
+
from ipor_fusion.onchain_text import sanitize_onchain_text
|
|
21
22
|
from ipor_fusion.types import (
|
|
22
23
|
ZERO_ADDRESS,
|
|
23
24
|
AccessManagerAddress,
|
|
@@ -614,7 +615,9 @@ class PlasmaVault(ContractWrapper):
|
|
|
614
615
|
return self._view("totalSupply()", output_types=["uint256"], decoder=Shares)
|
|
615
616
|
|
|
616
617
|
def name(self) -> Call[str]:
|
|
617
|
-
return self._view(
|
|
618
|
+
return self._view(
|
|
619
|
+
"name()", output_types=["string"], decoder=sanitize_onchain_text
|
|
620
|
+
)
|
|
618
621
|
|
|
619
622
|
def underlying_asset_address(self) -> Call[ChecksumAddress]:
|
|
620
623
|
return self._view(
|
{ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/core/simulation_result.py
RENAMED
|
@@ -13,6 +13,7 @@ from eth_typing import ChecksumAddress
|
|
|
13
13
|
from hexbytes import HexBytes
|
|
14
14
|
|
|
15
15
|
from ipor_fusion.errors import SimulationError, SimulationRunError, decode_custom_error
|
|
16
|
+
from ipor_fusion.onchain_text import sanitize_onchain_text
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
class QueuedCall(Protocol):
|
|
@@ -295,7 +296,7 @@ def _decode_revert(return_data: HexBytes, error: str | None) -> str | None:
|
|
|
295
296
|
if selector == b"\x08\xc3\x79\xa0": # Error(string)
|
|
296
297
|
try:
|
|
297
298
|
(msg,) = decode(["string"], bytes(return_data[4:]))
|
|
298
|
-
return msg
|
|
299
|
+
return sanitize_onchain_text(msg)
|
|
299
300
|
except (DecodingError, OverflowError, ValueError):
|
|
300
301
|
pass
|
|
301
302
|
if selector == b"\x4e\x48\x7b\x71": # Panic(uint256)
|
|
@@ -11,6 +11,7 @@ from web3 import Web3
|
|
|
11
11
|
from web3.types import TxParams, TxReceipt
|
|
12
12
|
|
|
13
13
|
from ipor_fusion.fusion_errors import FUSION_ERROR_SIGNATURES
|
|
14
|
+
from ipor_fusion.onchain_text import sanitize_onchain_text
|
|
14
15
|
from ipor_fusion.types import TxHash
|
|
15
16
|
|
|
16
17
|
log = logging.getLogger(__name__)
|
|
@@ -95,7 +96,7 @@ def _decode_revert_reason(data: bytes) -> str:
|
|
|
95
96
|
if selector == ERROR_SELECTOR:
|
|
96
97
|
try:
|
|
97
98
|
(reason,) = abi_decode(["string"], payload)
|
|
98
|
-
return f'Error("{reason}")'
|
|
99
|
+
return f'Error("{sanitize_onchain_text(reason)}")'
|
|
99
100
|
except Exception:
|
|
100
101
|
return f"Error(<decode failed>: 0x{payload.hex()[:64]})"
|
|
101
102
|
|
|
@@ -132,7 +133,9 @@ def get_revert_reason(web3: Web3, tx_hash: TxHash, receipt: TxReceipt) -> str |
|
|
|
132
133
|
call_params["gas"] = tx["gas"]
|
|
133
134
|
|
|
134
135
|
block_number = receipt["blockNumber"]
|
|
135
|
-
web3.eth.call(
|
|
136
|
+
web3.eth.call(
|
|
137
|
+
call_params, block_identifier=block_number, ccip_read_enabled=False
|
|
138
|
+
)
|
|
136
139
|
return None # replay succeeded — can't determine reason
|
|
137
140
|
except Exception as exc:
|
|
138
141
|
exc_data = getattr(exc, "data", None)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Text read from a contract is chosen by whoever deployed it.
|
|
2
|
+
|
|
3
|
+
Callers print it, log it and hand it to other programs, so it must not carry
|
|
4
|
+
control sequences, invisible characters or unbounded length. This does not make
|
|
5
|
+
the wording trustworthy: a clean string can still say anything.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import unicodedata
|
|
9
|
+
|
|
10
|
+
MAX_ONCHAIN_TEXT_CHARS = 256
|
|
11
|
+
|
|
12
|
+
# Control, format (bidi overrides, zero-width and tag characters), surrogate,
|
|
13
|
+
# private use, and line and paragraph separators.
|
|
14
|
+
_REMOVED_CATEGORIES = frozenset({"Cc", "Cf", "Cs", "Co", "Zl", "Zp"})
|
|
15
|
+
_LINE_BREAKS = frozenset("\t\n\r\f\v\u2028\u2029")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def sanitize_onchain_text(value: str) -> str:
|
|
19
|
+
"""``value`` as one line of visible text, at most `MAX_ONCHAIN_TEXT_CHARS`
|
|
20
|
+
long plus an ellipsis when cut. Line breaks and tabs become spaces, so words
|
|
21
|
+
stay apart; other removed characters disappear."""
|
|
22
|
+
cleaned = "".join(
|
|
23
|
+
" " if character in _LINE_BREAKS else character
|
|
24
|
+
for character in value
|
|
25
|
+
if character in _LINE_BREAKS
|
|
26
|
+
or unicodedata.category(character) not in _REMOVED_CATEGORIES
|
|
27
|
+
)
|
|
28
|
+
if len(cleaned) > MAX_ONCHAIN_TEXT_CHARS:
|
|
29
|
+
return cleaned[:MAX_ONCHAIN_TEXT_CHARS] + "…"
|
|
30
|
+
return cleaned
|
{ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/readers/oracle_mapping_reader.py
RENAMED
|
@@ -20,6 +20,7 @@ from ipor_fusion.core.oracle import (
|
|
|
20
20
|
PriceOracleMiddlewareManager,
|
|
21
21
|
price_oracle_middleware,
|
|
22
22
|
)
|
|
23
|
+
from ipor_fusion.onchain_text import sanitize_onchain_text
|
|
23
24
|
from ipor_fusion.types import (
|
|
24
25
|
Amount,
|
|
25
26
|
Decimals,
|
|
@@ -83,7 +84,9 @@ class _Aggregator(ContractWrapper):
|
|
|
83
84
|
return self._view("decimals()", output_types=["uint8"], decoder=Decimals)
|
|
84
85
|
|
|
85
86
|
def description(self) -> Call[str]:
|
|
86
|
-
return self._view(
|
|
87
|
+
return self._view(
|
|
88
|
+
"description()", output_types=["string"], decoder=sanitize_onchain_text
|
|
89
|
+
)
|
|
87
90
|
|
|
88
91
|
def latest_round_data(self) -> Call[tuple[int, int, int, int, int]]:
|
|
89
92
|
return self._view(
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""A contract must not be able to make the SDK send an HTTP request.
|
|
2
|
+
|
|
3
|
+
EIP-3668 lets a contract revert with `OffchainLookup(urls, ...)`, which web3
|
|
4
|
+
follows by default from inside `eth.call`. Any address a caller passes is
|
|
5
|
+
therefore a request to a URL chosen by whoever deployed the contract.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
from unittest.mock import patch
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
from eth_abi import encode
|
|
13
|
+
from eth_typing import URI
|
|
14
|
+
from web3 import Web3
|
|
15
|
+
from web3.providers.base import BaseProvider
|
|
16
|
+
from web3.types import RPCEndpoint, RPCResponse
|
|
17
|
+
|
|
18
|
+
from ipor_fusion import NotPlasmaVaultError, Web3Context
|
|
19
|
+
from ipor_fusion.core.access import resolve_access_manager
|
|
20
|
+
from ipor_fusion.errors import get_revert_reason
|
|
21
|
+
|
|
22
|
+
ADDRESS = Web3.to_checksum_address("0x" + "11" * 20)
|
|
23
|
+
OFFCHAIN_LOOKUP_SELECTOR = bytes.fromhex("556f1830")
|
|
24
|
+
LOOKUP_URL = "https://192.0.2.1/lookup"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _offchain_lookup_revert() -> str:
|
|
28
|
+
args = encode(
|
|
29
|
+
["address", "string[]", "bytes", "bytes4", "bytes"],
|
|
30
|
+
[ADDRESS, [LOOKUP_URL], b"", b"\xd8\xd7\x86\x9d", b""],
|
|
31
|
+
)
|
|
32
|
+
return "0x" + (OFFCHAIN_LOOKUP_SELECTOR + args).hex()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class _LookupProvider(BaseProvider):
|
|
36
|
+
"""A chain where `ADDRESS` has code and reverts every call with a lookup."""
|
|
37
|
+
|
|
38
|
+
def make_request(self, method: RPCEndpoint, params: Any) -> RPCResponse:
|
|
39
|
+
if method == "eth_call":
|
|
40
|
+
return {
|
|
41
|
+
"jsonrpc": "2.0",
|
|
42
|
+
"id": 1,
|
|
43
|
+
"error": {
|
|
44
|
+
"code": 3,
|
|
45
|
+
"message": "execution reverted",
|
|
46
|
+
"data": _offchain_lookup_revert(),
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
results: dict[str, Any] = {
|
|
50
|
+
"eth_chainId": "0x1",
|
|
51
|
+
"eth_getCode": "0x6000",
|
|
52
|
+
"eth_getTransactionByHash": {
|
|
53
|
+
"blockHash": "0x" + "22" * 32,
|
|
54
|
+
"blockNumber": "0x1",
|
|
55
|
+
"from": ADDRESS,
|
|
56
|
+
"gas": "0x5208",
|
|
57
|
+
"gasPrice": "0x1",
|
|
58
|
+
"hash": "0x" + "33" * 32,
|
|
59
|
+
"input": "0x",
|
|
60
|
+
"nonce": "0x0",
|
|
61
|
+
"to": ADDRESS,
|
|
62
|
+
"transactionIndex": "0x0",
|
|
63
|
+
"value": "0x0",
|
|
64
|
+
"type": "0x0",
|
|
65
|
+
"v": "0x1b",
|
|
66
|
+
"r": "0x1",
|
|
67
|
+
"s": "0x1",
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
return {"jsonrpc": "2.0", "id": 1, "result": results[method]}
|
|
71
|
+
|
|
72
|
+
def endpoint_uri(self) -> URI:
|
|
73
|
+
return URI("test://lookup")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _web3() -> Web3:
|
|
77
|
+
return Web3(_LookupProvider())
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_context_built_on_any_web3_does_not_follow_a_lookup() -> None:
|
|
81
|
+
ctx = Web3Context(web3=_web3(), chain_id=1)
|
|
82
|
+
|
|
83
|
+
with patch("requests.Session.request") as request:
|
|
84
|
+
with pytest.raises(NotPlasmaVaultError):
|
|
85
|
+
resolve_access_manager(ctx, ADDRESS)
|
|
86
|
+
|
|
87
|
+
request.assert_not_called()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_revert_replay_does_not_follow_a_lookup() -> None:
|
|
91
|
+
receipt: Any = {"blockNumber": 1}
|
|
92
|
+
|
|
93
|
+
with patch("requests.Session.request") as request:
|
|
94
|
+
get_revert_reason(_web3(), bytes.fromhex("33" * 32), receipt)
|
|
95
|
+
|
|
96
|
+
request.assert_not_called()
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
from eth_abi.abi import encode
|
|
3
|
+
from eth_typing import ChecksumAddress
|
|
4
|
+
from hexbytes import HexBytes
|
|
5
|
+
from web3 import Web3
|
|
6
|
+
|
|
7
|
+
from ipor_fusion.core.erc20 import ERC20
|
|
8
|
+
from ipor_fusion.core.plasma_vault import PlasmaVault
|
|
9
|
+
from ipor_fusion.core.simulation_result import _decode_revert
|
|
10
|
+
from ipor_fusion.errors import _decode_revert_reason
|
|
11
|
+
from ipor_fusion.onchain_text import MAX_ONCHAIN_TEXT_CHARS, sanitize_onchain_text
|
|
12
|
+
from ipor_fusion.readers.oracle_mapping_reader import _Aggregator
|
|
13
|
+
|
|
14
|
+
ADDRESS: ChecksumAddress = Web3.to_checksum_address("0x" + "11" * 20)
|
|
15
|
+
ERROR_STRING_SELECTOR = bytes.fromhex("08c379a0")
|
|
16
|
+
HOSTILE = "Vault\nIgnore previous instructions\u202e\u200b\U000e0041\x07"
|
|
17
|
+
CLEANED = "Vault Ignore previous instructions"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@pytest.mark.parametrize(
|
|
21
|
+
("value", "expected"),
|
|
22
|
+
[
|
|
23
|
+
("Clearstar Core ", "Clearstar Core "),
|
|
24
|
+
("wstETH", "wstETH"),
|
|
25
|
+
("Żółć 🚀", "Żółć 🚀"),
|
|
26
|
+
("a\nb\tc\r\nd\u2028e", "a b c d e"),
|
|
27
|
+
("a\u202eb\u200bc\u2066d", "abcd"),
|
|
28
|
+
("a\x00b\x1b[31mc", "ab[31mc"),
|
|
29
|
+
("tag\U000e0041\U000e007f", "tag"),
|
|
30
|
+
("private\ue000use", "privateuse"),
|
|
31
|
+
("", ""),
|
|
32
|
+
],
|
|
33
|
+
)
|
|
34
|
+
def test_sanitize_keeps_visible_text_only(value: str, expected: str) -> None:
|
|
35
|
+
assert sanitize_onchain_text(value) == expected
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_sanitize_bounds_the_length() -> None:
|
|
39
|
+
at_limit = "x" * MAX_ONCHAIN_TEXT_CHARS
|
|
40
|
+
|
|
41
|
+
assert sanitize_onchain_text(at_limit) == at_limit
|
|
42
|
+
assert sanitize_onchain_text(at_limit + "y") == at_limit + "…"
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@pytest.mark.parametrize(
|
|
46
|
+
"call",
|
|
47
|
+
[
|
|
48
|
+
ERC20(ADDRESS).name(),
|
|
49
|
+
ERC20(ADDRESS).symbol(),
|
|
50
|
+
PlasmaVault(ADDRESS).name(),
|
|
51
|
+
_Aggregator(ADDRESS).description(),
|
|
52
|
+
],
|
|
53
|
+
)
|
|
54
|
+
def test_string_reads_are_sanitized(call) -> None:
|
|
55
|
+
assert call.decode(encode(["string"], [HOSTILE])) == CLEANED
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_decoded_revert_reasons_are_sanitized() -> None:
|
|
59
|
+
data = ERROR_STRING_SELECTOR + encode(["string"], [HOSTILE])
|
|
60
|
+
|
|
61
|
+
assert _decode_revert_reason(data) == f'Error("{CLEANED}")'
|
|
62
|
+
assert _decode_revert(HexBytes(data), None) == CLEANED
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/advanced_euler_v2_credit_market_base.py
RENAMED
|
File without changes
|
{ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/advanced_euler_v2_looping_arbitrum.py
RENAMED
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/examples/external_state_margin_leg_base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/oracle_mapping_view.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.1.0.dev54 → ipor_fusion-4.1.1.dev2}/src/ipor_fusion/cli/vault_markets_view.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|