ipor-fusion 4.0.0.dev83__tar.gz → 4.0.0.dev88__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.dev83 → ipor_fusion-4.0.0.dev88}/AGENTS.md +8 -4
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/MIGRATION_4.md +87 -10
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/advanced_euler_v2_credit_market_base.py +2 -2
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/advanced_euler_v2_looping_arbitrum.py +2 -2
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/external_state_margin_leg_base.py +4 -4
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/simple_aave_v3_supply_base.py +2 -2
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/__init__.py +8 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/access.py +3 -8
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/contract.py +14 -30
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/external_state_executor.py +76 -48
- ipor_fusion-4.0.0.dev83/src/ipor_fusion/fuses/base.py → ipor_fusion-4.0.0.dev88/src/ipor_fusion/core/fuse.py +17 -8
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/multicall.py +6 -4
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/oracle.py +2 -2
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/plasma_vault.py +5 -9
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/simulation.py +9 -6
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/withdraw_manager.py +4 -4
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/chainlink.py +5 -4
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/indexer.py +51 -16
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/quote.py +7 -4
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/errors.py +51 -11
- ipor_fusion-4.0.0.dev88/src/ipor_fusion/fuses/base.py +17 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/crosschain/base.py +3 -6
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/crosschain/ccip.py +3 -2
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/crosschain/stargate.py +2 -1
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/universal.py +0 -10
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/mcp/server.py +1 -4
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/aave_v3.py +5 -3
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/hypercore.py +19 -8
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/hypercore_outcome.py +4 -1
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/morpho.py +3 -3
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_crosschain_recovery.py +1 -1
- ipor_fusion-4.0.0.dev88/tests/test_contract_encoder.py +118 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_ccip_indexer.py +52 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_ccip_quote.py +6 -3
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_chainlink.py +2 -1
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_layering.py +13 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_error_hierarchy.py +8 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_external_state_executor.py +59 -55
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_fee_manager.py +2 -2
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_fuse_encoding.py +17 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_hypercore_flow.py +3 -3
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_hypercore_outcome.py +12 -1
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_hypercore_readers.py +17 -3
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_mcp_server.py +1 -5
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_plasma_vault.py +1 -1
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_public_api.py +4 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_fusion_factory_clone_base.py +7 -23
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_plasma_vault_setters_base.py +1 -4
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_solidity_mirrors.py +1 -1
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_vault_simulator_blocks.py +3 -3
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/typed_client/consumer.py +8 -0
- ipor_fusion-4.0.0.dev83/tests/test_contract_encoder.py +0 -118
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/README.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/vault_data.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/uv.lock +0 -0
|
@@ -218,12 +218,14 @@ the lifecycle matrix follows that.
|
|
|
218
218
|
`simulation` (`VaultSimulator`, eth_simulateV1, `erc20_balance_slot` and ERC-20 balance
|
|
219
219
|
overrides), `oracle`, `fusion_factory`,
|
|
220
220
|
`external_state_executor` (NAV marks for market 50), `erc20`, `fuse_action`
|
|
221
|
-
(`FuseAction`), `
|
|
221
|
+
(`FuseAction`), `fuse` (the `Fuse` base, `StakeFuse`, the shared validators and
|
|
222
|
+
substrate packers), `address` (`_validate_not_zero_address`). `core` imports neither
|
|
222
223
|
`fuses` nor `crosschain` (`tests/test_sdk_layering.py`)
|
|
223
224
|
- `fuses/` — per-protocol fuse encoders (aave_v3, async_action, compound_v3, crosschain/,
|
|
224
225
|
erc4626, euler_v2, external_state, fluid_instadapp, gearbox_v3, merkl, morpho, ramses_v2,
|
|
225
|
-
uniswap_v3, universal, `events.py`); `base.py`
|
|
226
|
-
|
|
226
|
+
uniswap_v3, universal, `events.py`); `base.py` re-exports the `core/fuse.py` base and validators,
|
|
227
|
+
`FuseAction` and `ZERO_ADDRESS` (from `types`). A fuse is a value: equality and
|
|
228
|
+
hash cover its class and every attribute it stores
|
|
227
229
|
- `crosschain/` — crosschain Plasma Vaults (executor on the hub chain, dispatcher at
|
|
228
230
|
the same address on each spoke chain), split like the contracts: shared `messages`
|
|
229
231
|
(`Command`, `MsgType`, envelopes), `contracts` (wrapper bases), `transport`
|
|
@@ -276,7 +278,9 @@ or examples.
|
|
|
276
278
|
- `Call[T]` (`core/contract.py`): every `ContractWrapper` method (one per
|
|
277
279
|
Solidity function) returns a `Call` instead of executing. `.call()` runs
|
|
278
280
|
`eth_call` and decodes to `T`; `.send()` signs and submits, returning a
|
|
279
|
-
`TxReceipt`; `.calldata` hands the bytes to an external signer
|
|
281
|
+
`TxReceipt`; `.calldata` hands the bytes to an external signer (a wrapper
|
|
282
|
+
built with `ctx=None`, e.g. `PlasmaVault(None, address)`, builds calldata
|
|
283
|
+
offline; there is no separate encoder factory);
|
|
280
284
|
`.build_transaction()` / `Web3Context.estimate_gas` preview without signing.
|
|
281
285
|
A `Call` without `output_types` (a write) raises on `.call()`. The same
|
|
282
286
|
`Call` feeds `VaultSimulator.observe`, so reads, sends and simulations share
|
|
@@ -93,7 +93,7 @@ The Uniswap V3 / Ramses V2 position events' `version`, `sender` and `recipient`
|
|
|
93
93
|
`quote_ccip_native_fee(block=)` and `OracleMappingReader.asset_source_events` take a
|
|
94
94
|
`BlockIdentifier`.
|
|
95
95
|
|
|
96
|
-
**Address roles.** `PlasmaVault(ctx, address)`,
|
|
96
|
+
**Address roles.** `PlasmaVault(ctx, address)` (`ctx` may be `None`, see below),
|
|
97
97
|
`validate_vault`, `fetch_deployment_info`, the HyperCore, lending-health and
|
|
98
98
|
oracle-mapping readers, `read_external_state`, `VaultSimulator(vault=)`,
|
|
99
99
|
`CrosschainSimulator`, crosschain discovery, the hub-manager inputs
|
|
@@ -194,6 +194,35 @@ are `ProposalHash`; `ExternalStateEvent.transaction_hash` is a `TxHash`.
|
|
|
194
194
|
except below): `chain_id` fields are `ChainId`, `role_id` `RoleId`, `market_id`
|
|
195
195
|
`MarketId`. Calling an MCP tool function directly from Python takes `ChainId`.
|
|
196
196
|
|
|
197
|
+
**Offline wrappers.** `ContractWrapper.encoder()` (and the `PlasmaVault` /
|
|
198
|
+
`AccessManager` overrides) is gone. Every wrapper constructor takes
|
|
199
|
+
`ctx: Web3Context | None`, so build an offline wrapper with the normal
|
|
200
|
+
constructor and an address: `PlasmaVault(None, vault)`, `ERC20(None, token)`,
|
|
201
|
+
`FusionFactory(None, factory)`, `LegacyPriceOracleMiddleware(None, oracle,
|
|
202
|
+
Decimals(8))`. The address is required (there is no zero-address placeholder) and
|
|
203
|
+
subclass parameters stay required, so the wrapper is fully initialized:
|
|
204
|
+
`.encoder()` skipped the constructor, and a legacy oracle built that way failed to
|
|
205
|
+
decode `get_asset_price`. `.calldata` still needs no context; `.call()`, `.send()`,
|
|
206
|
+
`.build_transaction()` and `.estimate_gas()` raise `ValueError` until one is passed
|
|
207
|
+
to them, and a method that reads the chain itself (log scans such as
|
|
208
|
+
`get_balance_fuses` or `get_pending_requests`, `withdraw_manager_address`,
|
|
209
|
+
`Multicall3.aggregate` / `try_aggregate`, the Aave V3 and Morpho position reads)
|
|
210
|
+
raises `ValueError("Web3Context required: <wrapper> at <address> ...")` instead of
|
|
211
|
+
an `AttributeError` on `None`. `ExternalStateExecutor` still refuses the zero
|
|
212
|
+
address for its hash and event readers.
|
|
213
|
+
|
|
214
|
+
| 3.x | 4.0 |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `PlasmaVault.encoder(vault)` | `PlasmaVault(None, vault)` |
|
|
217
|
+
| `ERC20.encoder()` (no address) | `ERC20(None, token)`: pass the real address |
|
|
218
|
+
| `Cls.__new__(Cls)` + `_ctx` / `_address` | `Cls(None, address)` |
|
|
219
|
+
|
|
220
|
+
**Fuse base.** `Fuse`, `StakeFuse` and the shared validators and substrate packers
|
|
221
|
+
live in `ipor_fusion.core.fuse`; `ipor_fusion.fuses.base`, `ipor_fusion.fuses` and
|
|
222
|
+
`ipor_fusion` re-export them, so existing imports keep working. Fuse equality and
|
|
223
|
+
hash now cover every attribute a fuse stores, not only its class and address (see
|
|
224
|
+
[Behavior changes](#behavior-changes)).
|
|
225
|
+
|
|
197
226
|
**Moved, still importable.** `FuseAction` lives in `ipor_fusion.core.fuse_action` and
|
|
198
227
|
`ZERO_ADDRESS` in `ipor_fusion.types`; both are re-exported from
|
|
199
228
|
`ipor_fusion.fuses.base` and `FuseAction` from `ipor_fusion`. The CLI's internal
|
|
@@ -202,6 +231,12 @@ except below): `chain_id` fields are `ChainId`, `role_id` `RoleId`, `market_id`
|
|
|
202
231
|
|
|
203
232
|
## Behavior changes
|
|
204
233
|
|
|
234
|
+
- Two fuses are equal (and hash alike) only when they have the same class and the
|
|
235
|
+
same stored state. `StakeFuse` subclasses (`GearboxStakeFuse`,
|
|
236
|
+
`FluidInstadappStakingFuse`) with the same fuse address but different
|
|
237
|
+
`staking_address` were equal and collapsed in a set or dict key; they are now
|
|
238
|
+
distinct. A custom `Fuse` subclass is compared on its instance attributes, which
|
|
239
|
+
must be hashable; drop an `__eq__` / `__hash__` override that only added them.
|
|
205
240
|
- The MCP `vault_info` document reports the vault address checksummed (the CLI
|
|
206
241
|
already did).
|
|
207
242
|
- `SubstrateInfo.address` is `None` instead of `""` for a substrate without an
|
|
@@ -238,15 +273,20 @@ except below): `chain_id` fields are `ChainId`, `role_id` `RoleId`, `market_id`
|
|
|
238
273
|
## Errors
|
|
239
274
|
|
|
240
275
|
Every exception class the SDK defines now derives from `IporFusionError` and is
|
|
241
|
-
importable from `ipor_fusion`; the builtin bases they had are kept.
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
276
|
+
importable from `ipor_fusion`; the builtin bases they had are kept. One rule holds
|
|
277
|
+
across the whole SDK: a caller's mistake (a bad argument, or an operation the object
|
|
278
|
+
was not built for) raises a plain `ValueError` (`TypeError` for an argument of the
|
|
279
|
+
wrong type, `KeyError` for an unknown name in a mapping-style lookup such as
|
|
280
|
+
`ipor_fusion.guide.guide_text`); a chain, provider or remote API answering something the
|
|
281
|
+
SDK cannot use raises an `IporFusionError` subclass. Except for
|
|
282
|
+
`CrosschainDiscoveryError` (discovery) and `SimulationError` (`quote_ccip_native_fee`),
|
|
283
|
+
every subclass that replaces a `ValueError` raise also derives from `ValueError`, so
|
|
284
|
+
`except ValueError` keeps catching it; catch the subclass to tell a chain fact from a
|
|
285
|
+
bad argument. Receipts,
|
|
286
|
+
logs and transports passed in that do not contain what the call needs (a clone
|
|
287
|
+
receipt without its events, logs without the lane's `BalanceProposed`, a CCIP
|
|
288
|
+
message to a chain the transport does not configure) stay `ValueError`: the input
|
|
289
|
+
is the wrong one.
|
|
250
290
|
|
|
251
291
|
- `MorphoApiError` (still a `RuntimeError`), `ExternalStateEventDecodeError` (still a
|
|
252
292
|
`ValueError`) and `VerifierResultUnavailable` (still a `LookupError`) now derive
|
|
@@ -274,3 +314,40 @@ indexer answer, and `erc20_balance_slot` raises `ValueError` when no slot answer
|
|
|
274
314
|
- The Morpho API client raises `MorphoApiError` for every response it cannot read and
|
|
275
315
|
for any `OSError` or `http.client.HTTPException` while fetching (it caught only
|
|
276
316
|
`URLError` and `TimeoutError` before).
|
|
317
|
+
- The MCP `market_meta_morpho` tool lets `MorphoApiError` propagate instead of
|
|
318
|
+
re-raising it as `ValueError`. MCP clients see the same tool error message; only a
|
|
319
|
+
direct Python call of the tool function sees the new type.
|
|
320
|
+
- `read_hypercore_nav` (and `read_hypercore_vault_state`, which calls it) raises the new
|
|
321
|
+
`HyperCoreValuationError` (still a `ValueError`) for a failed `spotBalance`,
|
|
322
|
+
`tokenInfo` or `accountMarginSummary` precompile read, a granted spot token the
|
|
323
|
+
oracle does not price, a price overflow and an unsupported HIP-3 dex bitmap;
|
|
324
|
+
`HyperCoreNav.balance_wad` raises it for a negative NAV.
|
|
325
|
+
- `read_hypercore_transfer_snapshot` raises `UnsupportedChainError` (still a
|
|
326
|
+
`ValueError`) on a chain with no known `HyperCorePendingReader` when none is passed.
|
|
327
|
+
- `fetch_verifier_result` no longer leaks `KeyError`, `TypeError` or `ValueError` from
|
|
328
|
+
an indexer answer it cannot read (not JSON, a missing or mistyped field, invalid hex
|
|
329
|
+
or address, an empty or non-array CCV list, or a result for a different message id,
|
|
330
|
+
both now checked): that
|
|
331
|
+
indexer is skipped like an unreachable one, and when none serves a readable result
|
|
332
|
+
it raises `VerifierResultUnavailable` naming each indexer's reason. A `message_id`
|
|
333
|
+
that is not 32 bytes is still a `ValueError`.
|
|
334
|
+
- `erc20_balance_slot` raises the new `BalanceSlotNotFoundError` (still a
|
|
335
|
+
`ValueError`) when no slot up to `max_slot` answers as the balances mapping; a
|
|
336
|
+
negative `max_slot` is a `ValueError` with its own message.
|
|
337
|
+
- The external-state market raises the new `ExternalStateError` (still a
|
|
338
|
+
`ValueError`): `read_external_state` for a storage word longer than 32 bytes, an
|
|
339
|
+
executor word with bits above the address or a pause word other than 0 or 1;
|
|
340
|
+
`ExternalStateExecutor.for_vault` when no executor is deployed and, instead of
|
|
341
|
+
eth_abi's `NonEmptyPaddingBytes`, for a slot that is not an address;
|
|
342
|
+
`parse_balance_proposed` / `find_balance_proposed` for one of the executor's own
|
|
343
|
+
`BalanceProposed` logs whose data is missing or malformed (including data that is
|
|
344
|
+
not hex at all, which raised `TypeError`) or whose hash is not the hash of its own
|
|
345
|
+
fields; and `mark_nav` when the propose receipt it fetched has no such log or
|
|
346
|
+
records another value or proposer. A log that is not the event or not from the
|
|
347
|
+
executor, and `find_balance_proposed` over logs that hold no match, are still
|
|
348
|
+
`ValueError`.
|
|
349
|
+
- `ccip_token_lane` raises the new `UnsupportedContractVersionError` (still a
|
|
350
|
+
`ValueError`) for an OnRamp version whose layout is not verified.
|
|
351
|
+
- `quote_ccip_native_fee` raises `SimulationError` (label `"quote"`, with
|
|
352
|
+
`revert_reason`) instead of `ValueError` when the call reverts before the CCIP fee
|
|
353
|
+
check. A call that succeeds without sending a message is still a `ValueError`.
|
{ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/advanced_euler_v2_credit_market_base.py
RENAMED
|
@@ -261,12 +261,12 @@ def clone_args() -> dict:
|
|
|
261
261
|
def unsigned_clone_calldata() -> bytes:
|
|
262
262
|
"""Unsigned creation calldata (selector + ABI-encoded args) for the deploy.
|
|
263
263
|
|
|
264
|
-
Built
|
|
264
|
+
Built on a wrapper with ctx=None, so it needs no provider. Hand these bytes to
|
|
265
265
|
an external signer / multisig instead of calling ``.send()``. NOTE: the owner
|
|
266
266
|
encoded here is the simulation ``OWNER`` (a throwaway EOA) -- set your real
|
|
267
267
|
owner in ``clone_args()`` before deploying, or the vault is owned by it.
|
|
268
268
|
"""
|
|
269
|
-
return FusionFactory
|
|
269
|
+
return FusionFactory(None, BASE_FUSION_FACTORY).clone(**clone_args()).calldata
|
|
270
270
|
|
|
271
271
|
|
|
272
272
|
def market_substrates() -> list[bytes]:
|
{ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/advanced_euler_v2_looping_arbitrum.py
RENAMED
|
@@ -208,7 +208,7 @@ def clone_args() -> dict:
|
|
|
208
208
|
|
|
209
209
|
|
|
210
210
|
def unsigned_clone_calldata() -> bytes:
|
|
211
|
-
return FusionFactory
|
|
211
|
+
return FusionFactory(None, ARBITRUM_FUSION_FACTORY).clone(**clone_args()).calldata
|
|
212
212
|
|
|
213
213
|
|
|
214
214
|
def euler_market_substrates() -> list[bytes]:
|
|
@@ -260,7 +260,7 @@ def enable_euler_actions() -> list[FuseAction]:
|
|
|
260
260
|
def build_swap_action() -> FuseAction:
|
|
261
261
|
"""Swap the borrowed USDC through Uniswap V3 and require flash repayment."""
|
|
262
262
|
transfer_data = (
|
|
263
|
-
ERC20
|
|
263
|
+
ERC20(None, ARBITRUM_USDC)
|
|
264
264
|
.transfer(UNISWAP_UNIVERSAL_ROUTER, BORROW_USDC)
|
|
265
265
|
.calldata
|
|
266
266
|
)
|
{ipor_fusion-4.0.0.dev83 → ipor_fusion-4.0.0.dev88}/examples/external_state_margin_leg_base.py
RENAMED
|
@@ -438,12 +438,12 @@ def clone_args() -> dict:
|
|
|
438
438
|
def unsigned_clone_calldata() -> bytes:
|
|
439
439
|
"""Unsigned creation calldata (selector + ABI-encoded args) for the deploy.
|
|
440
440
|
|
|
441
|
-
Built
|
|
441
|
+
Built on a wrapper with ctx=None, so it needs no provider. Hand these bytes to
|
|
442
442
|
an external signer / multisig instead of calling ``.send()``. NOTE: the owner
|
|
443
443
|
encoded here is the simulation ``OWNER`` (a throwaway EOA) -- set your real
|
|
444
444
|
owner in ``clone_args()`` before deploying, or the vault is owned by it.
|
|
445
445
|
"""
|
|
446
|
-
return FusionFactory
|
|
446
|
+
return FusionFactory(None, BASE_FUSION_FACTORY).clone(**clone_args()).calldata
|
|
447
447
|
|
|
448
448
|
|
|
449
449
|
def market_substrates() -> list[bytes]:
|
|
@@ -534,9 +534,9 @@ def market_substrates() -> list[bytes]:
|
|
|
534
534
|
def venue_transfer_calldata(amount: Amount) -> bytes:
|
|
535
535
|
"""``USDC.transfer(VENUE_DEPOSIT_ADDRESS, amount)`` calldata, run from the executor.
|
|
536
536
|
|
|
537
|
-
Encoded with
|
|
537
|
+
Encoded with an ERC20 wrapper built with ctx=None -- pure bytes, no chain access.
|
|
538
538
|
"""
|
|
539
|
-
return ERC20
|
|
539
|
+
return ERC20(None, BASE_USDC).transfer(VENUE_DEPOSIT_ADDRESS, amount).calldata
|
|
540
540
|
|
|
541
541
|
|
|
542
542
|
def build_enter_action(amount: Amount) -> FuseAction:
|
|
@@ -201,12 +201,12 @@ def clone_args() -> dict:
|
|
|
201
201
|
def unsigned_clone_calldata() -> bytes:
|
|
202
202
|
"""Unsigned creation calldata (selector + ABI-encoded args) for the deploy.
|
|
203
203
|
|
|
204
|
-
Built
|
|
204
|
+
Built on a wrapper with ctx=None, so it needs no provider. Hand these bytes to
|
|
205
205
|
an external signer / multisig instead of calling ``.send()``. NOTE: the owner
|
|
206
206
|
encoded here is the simulation ``OWNER`` (a throwaway EOA) -- set your real
|
|
207
207
|
owner in ``clone_args()`` before deploying, or the vault is owned by it.
|
|
208
208
|
"""
|
|
209
|
-
return FusionFactory
|
|
209
|
+
return FusionFactory(None, BASE_FUSION_FACTORY).clone(**clone_args()).calldata
|
|
210
210
|
|
|
211
211
|
|
|
212
212
|
def build_supply_action(amount: Amount) -> FuseAction:
|
|
@@ -173,9 +173,12 @@ from ipor_fusion.dependency_graph import (
|
|
|
173
173
|
)
|
|
174
174
|
from ipor_fusion.errors import (
|
|
175
175
|
CUSTOM_ERRORS,
|
|
176
|
+
BalanceSlotNotFoundError,
|
|
176
177
|
ContractNotFoundError,
|
|
177
178
|
CrosschainDiscoveryError,
|
|
178
179
|
EmptyCallResultError,
|
|
180
|
+
ExternalStateError,
|
|
181
|
+
HyperCoreValuationError,
|
|
179
182
|
IporFusionError,
|
|
180
183
|
LogScanError,
|
|
181
184
|
LogSourceUnavailable,
|
|
@@ -185,6 +188,7 @@ from ipor_fusion.errors import (
|
|
|
185
188
|
SimulationRunError,
|
|
186
189
|
TransactionError,
|
|
187
190
|
UnsupportedChainError,
|
|
191
|
+
UnsupportedContractVersionError,
|
|
188
192
|
UnsupportedVaultVersionError,
|
|
189
193
|
decode_custom_error,
|
|
190
194
|
get_revert_reason,
|
|
@@ -717,9 +721,12 @@ __all__ = [
|
|
|
717
721
|
"format_market_label",
|
|
718
722
|
"market_name",
|
|
719
723
|
"DOCS",
|
|
724
|
+
"BalanceSlotNotFoundError",
|
|
720
725
|
"ContractNotFoundError",
|
|
721
726
|
"CrosschainDiscoveryError",
|
|
722
727
|
"EmptyCallResultError",
|
|
728
|
+
"ExternalStateError",
|
|
729
|
+
"HyperCoreValuationError",
|
|
723
730
|
"IporFusionError",
|
|
724
731
|
"LogScanError",
|
|
725
732
|
"LogSourceUnavailable",
|
|
@@ -729,6 +736,7 @@ __all__ = [
|
|
|
729
736
|
"SimulationError",
|
|
730
737
|
"SimulationRunError",
|
|
731
738
|
"UnsupportedChainError",
|
|
739
|
+
"UnsupportedContractVersionError",
|
|
732
740
|
"UnsupportedVaultVersionError",
|
|
733
741
|
"CUSTOM_ERRORS",
|
|
734
742
|
"decode_custom_error",
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from collections.abc import Callable
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
-
from typing import Self
|
|
4
3
|
|
|
5
4
|
from eth_abi import decode
|
|
6
5
|
from eth_abi.exceptions import InsufficientDataBytes
|
|
@@ -68,17 +67,13 @@ def _role_status_decoder(values: tuple) -> RoleStatus:
|
|
|
68
67
|
class AccessManager(ContractWrapper):
|
|
69
68
|
"""Manages role-based access control for PlasmaVault operations."""
|
|
70
69
|
|
|
71
|
-
def __init__(self, ctx: Web3Context, address: AccessManagerAddress):
|
|
70
|
+
def __init__(self, ctx: Web3Context | None, address: AccessManagerAddress):
|
|
72
71
|
super().__init__(ctx, address)
|
|
73
72
|
|
|
74
73
|
@property
|
|
75
74
|
def address(self) -> AccessManagerAddress:
|
|
76
75
|
return AccessManagerAddress(self._address)
|
|
77
76
|
|
|
78
|
-
@classmethod
|
|
79
|
-
def encoder(cls, address: AccessManagerAddress | None = None) -> Self: # type: ignore[override]
|
|
80
|
-
return super().encoder(address)
|
|
81
|
-
|
|
82
77
|
def grant_role(
|
|
83
78
|
self, role_id: RoleId | Roles, account: ChecksumAddress, execution_delay: Period
|
|
84
79
|
) -> Call[None]:
|
|
@@ -161,7 +156,7 @@ class AccessManager(ContractWrapper):
|
|
|
161
156
|
if predicate(role_id, account):
|
|
162
157
|
candidates[(role_id, account)] = None
|
|
163
158
|
|
|
164
|
-
statuses = Multicall3(self.
|
|
159
|
+
statuses = Multicall3(self._require_ctx()).aggregate(
|
|
165
160
|
[self.has_role(role_id, account) for role_id, account in candidates]
|
|
166
161
|
)
|
|
167
162
|
return [
|
|
@@ -180,7 +175,7 @@ class AccessManager(ContractWrapper):
|
|
|
180
175
|
Web3.keccak(text="RoleGranted(uint64,address,uint32,uint48,bool)")
|
|
181
176
|
).to_0x_hex()
|
|
182
177
|
return list(
|
|
183
|
-
self.
|
|
178
|
+
self._require_ctx().get_logs(
|
|
184
179
|
contract_address=self._address, topics=[event_signature_hash]
|
|
185
180
|
)
|
|
186
181
|
)
|
|
@@ -129,18 +129,19 @@ class Call(Generic[T]):
|
|
|
129
129
|
return actual
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
_ENCODER_PLACEHOLDER_ADDRESS: ChecksumAddress = cast(
|
|
133
|
-
ChecksumAddress, "0x0000000000000000000000000000000000000000"
|
|
134
|
-
)
|
|
135
|
-
|
|
136
|
-
|
|
137
132
|
class ContractWrapper:
|
|
138
133
|
"""Base wrapper. Subclasses expose one method per Solidity function that
|
|
139
134
|
returns a `Call[T]` — never executing eagerly. Callers chain `.call()` for
|
|
140
135
|
reads, `.send()` for writes, or hand the `Call` to `VaultSimulator`.
|
|
136
|
+
|
|
137
|
+
`ctx` may be ``None`` for offline use, e.g. external-signer flows (HTTP
|
|
138
|
+
signing service, multisig) that only need `Call.calldata`: every builder
|
|
139
|
+
works, and `.call()` / `.send()` on its Calls raise until a context is
|
|
140
|
+
passed to them. Methods that read the chain themselves (log scans, storage
|
|
141
|
+
reads, batched reads) raise `ValueError` on such a wrapper.
|
|
141
142
|
"""
|
|
142
143
|
|
|
143
|
-
def __init__(self, ctx: Web3Context, address: ChecksumAddress):
|
|
144
|
+
def __init__(self, ctx: Web3Context | None, address: ChecksumAddress):
|
|
144
145
|
self._ctx = ctx
|
|
145
146
|
self._address = Web3.to_checksum_address(address)
|
|
146
147
|
|
|
@@ -148,30 +149,13 @@ class ContractWrapper:
|
|
|
148
149
|
def address(self) -> ChecksumAddress:
|
|
149
150
|
return self._address
|
|
150
151
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
access, decoders included. Calling `.call()` or `.send()` on a Call
|
|
159
|
-
produced this way raises (no ctx).
|
|
160
|
-
|
|
161
|
-
Pass `address` unless `.calldata` really is the only consumer. The
|
|
162
|
-
encoding ignores it, but a builder that reads `self._address`
|
|
163
|
-
semantically — matching it against a log's emitter, say, or folding it
|
|
164
|
-
into a hash — runs against the placeholder zero address without one,
|
|
165
|
-
and so rejects input that is genuinely the caller's.
|
|
166
|
-
"""
|
|
167
|
-
instance = cls.__new__(cls)
|
|
168
|
-
instance._ctx = None
|
|
169
|
-
instance._address = (
|
|
170
|
-
Web3.to_checksum_address(address)
|
|
171
|
-
if address is not None
|
|
172
|
-
else _ENCODER_PLACEHOLDER_ADDRESS
|
|
173
|
-
)
|
|
174
|
-
return instance
|
|
152
|
+
def _require_ctx(self) -> Web3Context:
|
|
153
|
+
if self._ctx is None:
|
|
154
|
+
raise ValueError(
|
|
155
|
+
f"Web3Context required: {type(self).__name__} at {self._address} "
|
|
156
|
+
"was built without one (ctx=None), which only builds calldata."
|
|
157
|
+
)
|
|
158
|
+
return self._ctx
|
|
175
159
|
|
|
176
160
|
def _view(
|
|
177
161
|
self,
|