ipor-fusion 4.0.0.dev126__tar.gz → 4.0.0.dev129__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.dev126 → ipor_fusion-4.0.0.dev129}/MIGRATION_4.md +8 -7
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/CONTRIBUTING.md +1 -5
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/external_state_margin_leg_base.py +0 -7
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/__init__.py +0 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/external_state_executor.py +20 -160
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/errors.py +2 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_external_state_executor.py +6 -362
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_public_api.py +0 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/AGENTS.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/README.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/mcp/server.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_data.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/tests/typed_client/rejected.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/uv.lock +0 -0
|
@@ -255,8 +255,11 @@ before passing it on.
|
|
|
255
255
|
`HyperCorePendingState` and `HyperCoreTransferSnapshot` carry them.
|
|
256
256
|
|
|
257
257
|
**External state.** `ExternalStateExecutor.proposal_hash` returns and `confirm_balance`
|
|
258
|
-
takes a `ProposalHash`; `BalanceProposal.proposal_hash`
|
|
259
|
-
|
|
258
|
+
takes a `ProposalHash`; `BalanceProposal.proposal_hash` is a `ProposalHash`;
|
|
259
|
+
`ExternalStateEvent.transaction_hash` is a `TxHash`.
|
|
260
|
+
`ExternalStateExecutor.mark_nav` and `NavMark` are gone: send `propose_balance` and
|
|
261
|
+
`confirm_balance` from separate custodians, then
|
|
262
|
+
`PlasmaVault.update_markets_balances([IporFusionMarkets.EXTERNAL_STATE])`.
|
|
260
263
|
|
|
261
264
|
**Errors and explorer.** `TransactionError(tx_hash=)` takes a `TxHash`,
|
|
262
265
|
`LogScanError(address=)` a `ChecksumAddress`; `get_revert_reason` takes a `TxHash`;
|
|
@@ -349,7 +352,7 @@ placeholder wrapper.
|
|
|
349
352
|
and `VaultSimulator.observe` stamp the same hash for the same bytes, whatever
|
|
350
353
|
context executes them. Pass `ctx.chain_id` for the chain you read from.
|
|
351
354
|
`pending_proposals` now refuses an executor at the zero address when the Call is
|
|
352
|
-
built, not when it is decoded.
|
|
355
|
+
built, not when it is decoded.
|
|
353
356
|
|
|
354
357
|
| 3.x | 4.0 |
|
|
355
358
|
|---|---|
|
|
@@ -560,10 +563,8 @@ is the wrong one.
|
|
|
560
563
|
`parse_balance_proposed` / `find_balance_proposed` for one of the executor's own
|
|
561
564
|
`BalanceProposed` logs whose data is missing or malformed (including data that is
|
|
562
565
|
not hex at all, which raised `TypeError`) or whose hash is not the hash of its own
|
|
563
|
-
fields
|
|
564
|
-
|
|
565
|
-
executor, and `find_balance_proposed` over logs that hold no match, are still
|
|
566
|
-
`ValueError`.
|
|
566
|
+
fields. A log that is not the event or not from the executor, and
|
|
567
|
+
`find_balance_proposed` over logs that hold no match, are still `ValueError`.
|
|
567
568
|
- `ccip_token_lane` raises the new `UnsupportedContractVersionError` (still a
|
|
568
569
|
`ValueError`) for an OnRamp version whose layout is not verified.
|
|
569
570
|
- `quote_ccip_native_fee` raises `SimulationError` (label `"quote"`, with
|
|
@@ -63,11 +63,7 @@ role-separation note is about. Label the collapse itself, not the calls: sending
|
|
|
63
63
|
as two separate calls *is* the production shape, and only "both keys in one process" is
|
|
64
64
|
simulation-only.
|
|
65
65
|
|
|
66
|
-
Cross-reference the SDK method a production caller would use instead, where one exists
|
|
67
|
-
where the SDK method is the one to reach for. `ExternalStateExecutor.mark_nav` is the counter-example:
|
|
68
|
-
it composes both custodian calls, its own docstring warns that this "does not preserve the
|
|
69
|
-
dual-custodian separation", and it is expected to be deprecated in favour of the two primitives. Do
|
|
70
|
-
not point readers at it.
|
|
66
|
+
Cross-reference the SDK method a production caller would use instead, where one exists.
|
|
71
67
|
|
|
72
68
|
## 3. One self-contained file
|
|
73
69
|
|
{ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev129}/examples/external_state_margin_leg_base.py
RENAMED
|
@@ -894,13 +894,6 @@ def run_simulation(web3: Web3) -> SimulationResult:
|
|
|
894
894
|
# driven from this one process. In a real deployment they live in separate
|
|
895
895
|
# systems -- if one process can send both, a single compromise moves the
|
|
896
896
|
# vault's NAV and the two-party design has bought nothing.
|
|
897
|
-
#
|
|
898
|
-
# ExternalStateExecutor.mark_nav runs the propose, the confirm and -- when
|
|
899
|
-
# handed a vault -- the refresh in one call. It cannot be used here for a
|
|
900
|
-
# mechanical reason: it .send(ctx)s each leg, and nothing is broadcast under
|
|
901
|
-
# eth_simulateV1. It is also not what a production deployment wants, for the
|
|
902
|
-
# reason above: one process holding both custodian keys is one key wearing
|
|
903
|
-
# two hats.
|
|
904
897
|
sim.next_block().with_block_time_shift(PROPOSE_OFFSET)
|
|
905
898
|
sim.add_call(
|
|
906
899
|
call=executor.propose_balance(VENUE_BALANCE_ACCOUNT, MARGIN_AMOUNT),
|
|
@@ -39,7 +39,6 @@ from ipor_fusion.core.external_state_executor import (
|
|
|
39
39
|
BalanceProposal,
|
|
40
40
|
ExternalStateExecutor,
|
|
41
41
|
ExternalStateVaultState,
|
|
42
|
-
NavMark,
|
|
43
42
|
RawLog,
|
|
44
43
|
read_external_state,
|
|
45
44
|
)
|
|
@@ -553,7 +552,6 @@ __all__ = [
|
|
|
553
552
|
"BalanceFuseSnapshot",
|
|
554
553
|
"ExternalStateVaultState",
|
|
555
554
|
"read_external_state",
|
|
556
|
-
"NavMark",
|
|
557
555
|
"CrosschainExecutor",
|
|
558
556
|
"StargateCrosschainExecutor",
|
|
559
557
|
"StargateCrosschainDispatcher",
|
|
@@ -6,20 +6,19 @@ by the external-state market. Its address lives in the VAULT's ERC-7201 storage
|
|
|
6
6
|
|
|
7
7
|
NAV for the external-state market is marked by a dual-custodian propose/confirm
|
|
8
8
|
on this executor, then a `update_markets_balances([EXTERNAL_STATE])` refresh on
|
|
9
|
-
the vault.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
confirmed for an account.
|
|
9
|
+
the vault. The confirming custodian's service reads `pending_proposals` and
|
|
10
|
+
confirms the hash it returns, never guessing the executor's global nonce. The
|
|
11
|
+
same proposal reaches an offline reader through the `BalanceProposed` event --
|
|
12
|
+
`find_balance_proposed` picks it out of a receipt's logs,
|
|
13
|
+
`parse_balance_proposed` decodes one row from an index -- and `balances` and
|
|
14
|
+
`last_updated` report what the custodians last confirmed for an account.
|
|
16
15
|
"""
|
|
17
16
|
|
|
18
17
|
from __future__ import annotations
|
|
19
18
|
|
|
20
19
|
from collections.abc import Iterable, Mapping
|
|
21
20
|
from dataclasses import dataclass, replace
|
|
22
|
-
from typing import
|
|
21
|
+
from typing import Any
|
|
23
22
|
|
|
24
23
|
from eth_abi import decode, encode
|
|
25
24
|
from eth_abi.exceptions import DecodingError
|
|
@@ -27,25 +26,19 @@ from eth_typing import ChecksumAddress
|
|
|
27
26
|
from eth_utils import keccak
|
|
28
27
|
from hexbytes import HexBytes
|
|
29
28
|
from web3 import Web3
|
|
30
|
-
from web3.types import BlockIdentifier
|
|
29
|
+
from web3.types import BlockIdentifier
|
|
31
30
|
|
|
32
31
|
from ipor_fusion.core.context import Web3Context
|
|
33
32
|
from ipor_fusion.core.contract import Call, ContractWrapper
|
|
34
33
|
from ipor_fusion.errors import ExternalStateError
|
|
35
|
-
from ipor_fusion.market_ids import IporFusionMarkets
|
|
36
34
|
from ipor_fusion.types import (
|
|
37
35
|
ZERO_ADDRESS,
|
|
38
36
|
Amount,
|
|
39
37
|
ChainId,
|
|
40
|
-
MarketId,
|
|
41
38
|
PlasmaVaultAddress,
|
|
42
39
|
ProposalHash,
|
|
43
40
|
)
|
|
44
41
|
|
|
45
|
-
if TYPE_CHECKING:
|
|
46
|
-
from ipor_fusion.core.plasma_vault import PlasmaVault
|
|
47
|
-
|
|
48
|
-
|
|
49
42
|
# The log shapes the event readers below accept: a receipt log from web3.py
|
|
50
43
|
# (HexBytes fields, checksummed address), and a raw JSON-RPC or
|
|
51
44
|
# `eth_simulateV1` row (0x-hex strings, lowercase address). Looser than
|
|
@@ -108,17 +101,6 @@ def _hash_of(
|
|
|
108
101
|
)
|
|
109
102
|
|
|
110
103
|
|
|
111
|
-
def _no_balance_proposed(
|
|
112
|
-
executor: ChecksumAddress, balance_account: ChecksumAddress | None
|
|
113
|
-
) -> str:
|
|
114
|
-
for_account = (
|
|
115
|
-
f" for account {Web3.to_checksum_address(balance_account)}"
|
|
116
|
-
if balance_account is not None
|
|
117
|
-
else ""
|
|
118
|
-
)
|
|
119
|
-
return f"no BalanceProposed log from executor {executor}{for_account}"
|
|
120
|
-
|
|
121
|
-
|
|
122
104
|
def _require_matching_hash(
|
|
123
105
|
proposal: BalanceProposal, *, executor: ChecksumAddress, chain_id: ChainId
|
|
124
106
|
) -> None:
|
|
@@ -141,22 +123,6 @@ def _require_matching_hash(
|
|
|
141
123
|
)
|
|
142
124
|
|
|
143
125
|
|
|
144
|
-
@dataclass(frozen=True, slots=True)
|
|
145
|
-
class NavMark:
|
|
146
|
-
"""Outcome of a `mark_nav` run: the confirmed proposal plus every receipt.
|
|
147
|
-
|
|
148
|
-
`refresh_receipt` is `None` when `mark_nav` was called without a `vault`
|
|
149
|
-
(propose + confirm only, no cached-NAV refresh).
|
|
150
|
-
"""
|
|
151
|
-
|
|
152
|
-
proposed_at: int
|
|
153
|
-
nonce: int
|
|
154
|
-
proposal_hash: ProposalHash
|
|
155
|
-
propose_receipt: TxReceipt
|
|
156
|
-
confirm_receipt: TxReceipt
|
|
157
|
-
refresh_receipt: TxReceipt | None
|
|
158
|
-
|
|
159
|
-
|
|
160
126
|
@dataclass(frozen=True, slots=True)
|
|
161
127
|
class ExternalStateVaultState:
|
|
162
128
|
"""The external-state market's vault-scoped state, read from the vault's
|
|
@@ -516,7 +482,8 @@ class ExternalStateExecutor(ContractWrapper):
|
|
|
516
482
|
) -> Call[None]:
|
|
517
483
|
"""CUSTODIAN-only: propose `value` (underlying units) as the new tracked
|
|
518
484
|
balance of `balance_account`. Confirm it from a *different* custodian
|
|
519
|
-
with `confirm_balance
|
|
485
|
+
with `confirm_balance`, then refresh the vault's cached NAV with
|
|
486
|
+
`PlasmaVault.update_markets_balances([EXTERNAL_STATE])`."""
|
|
520
487
|
return self._write("proposeBalance(address,uint256)", balance_account, value)
|
|
521
488
|
|
|
522
489
|
def confirm_balance(
|
|
@@ -743,18 +710,6 @@ class ExternalStateExecutor(ContractWrapper):
|
|
|
743
710
|
silently skips, and over a range you filtered yourself a foreign log
|
|
744
711
|
means the filter is wrong, not that the row is uninteresting.
|
|
745
712
|
"""
|
|
746
|
-
found = self._last_balance_proposed(logs, balance_account, chain_id)
|
|
747
|
-
if found is not None:
|
|
748
|
-
return found
|
|
749
|
-
raise ValueError(_no_balance_proposed(self._address, balance_account))
|
|
750
|
-
|
|
751
|
-
def _last_balance_proposed(
|
|
752
|
-
self,
|
|
753
|
-
logs: Iterable[RawLog],
|
|
754
|
-
balance_account: ChecksumAddress | None,
|
|
755
|
-
chain_id: ChainId,
|
|
756
|
-
) -> BalanceProposal | None:
|
|
757
|
-
"""`find_balance_proposed` without the raise when nothing matches."""
|
|
758
713
|
self._require_address()
|
|
759
714
|
wanted = (
|
|
760
715
|
Web3.to_checksum_address(balance_account)
|
|
@@ -770,111 +725,16 @@ class ExternalStateExecutor(ContractWrapper):
|
|
|
770
725
|
proposal = self._decode_balance_proposed(log)
|
|
771
726
|
if wanted is None or proposal.balance_account == wanted:
|
|
772
727
|
found = proposal
|
|
773
|
-
if found is
|
|
774
|
-
|
|
775
|
-
# actually being returned.
|
|
776
|
-
_require_matching_hash(
|
|
777
|
-
found,
|
|
778
|
-
executor=self._address,
|
|
779
|
-
chain_id=chain_id,
|
|
780
|
-
)
|
|
781
|
-
return found
|
|
782
|
-
|
|
783
|
-
def mark_nav(
|
|
784
|
-
self,
|
|
785
|
-
*,
|
|
786
|
-
value: Amount,
|
|
787
|
-
balance_account: ChecksumAddress,
|
|
788
|
-
proposer_ctx: Web3Context,
|
|
789
|
-
confirmer_ctx: Web3Context,
|
|
790
|
-
vault: PlasmaVault | None = None,
|
|
791
|
-
) -> NavMark:
|
|
792
|
-
"""Mark the external-state NAV: propose `value` (custodian A), confirm it
|
|
793
|
-
(custodian B), and optionally refresh the vault's cached NAV.
|
|
794
|
-
|
|
795
|
-
`proposer_ctx` signs the propose; `confirmer_ctx` signs the confirm (and,
|
|
796
|
-
when `vault` is given, the `update_markets_balances([EXTERNAL_STATE])`
|
|
797
|
-
refresh). The two signers MUST be different custodians, and MUST be on
|
|
798
|
-
the same chain; both are checked before the propose is sent, since the
|
|
799
|
-
hash is chain-bound and a mismatch would otherwise only surface with a
|
|
800
|
-
proposal already stranded on the proposer's chain. The confirm hash,
|
|
801
|
-
nonce, and timestamp are taken from the propose tx's `BalanceProposed`
|
|
802
|
-
event -- exactly what the contract stored, so no read can race the
|
|
803
|
-
executor's global nonce. Returns a `NavMark` with the proposal and every
|
|
804
|
-
receipt.
|
|
805
|
-
|
|
806
|
-
The marked balance is valued into the vault's `totalAssets` via the
|
|
807
|
-
external-state market (50), so it moves the share price; the refresh is
|
|
808
|
-
what propagates the new value into the vault's cached NAV.
|
|
809
|
-
|
|
810
|
-
Sends up to three transactions and blocks on each; see `NavMark`. If the
|
|
811
|
-
propose receipt does not record the value and proposer this call sent,
|
|
812
|
-
or carries a hash that is not the hash of those fields, it raises rather
|
|
813
|
-
than confirming -- note the propose transaction has already landed at
|
|
814
|
-
that point, leaving a pending proposal behind.
|
|
815
|
-
|
|
816
|
-
Security: mark_nav composes `propose_balance` + `confirm_balance`, so it
|
|
817
|
-
needs both custodian keys in one process and does not preserve the
|
|
818
|
-
dual-custodian separation. When that separation is the point, run the two
|
|
819
|
-
primitives from separate services instead.
|
|
820
|
-
"""
|
|
821
|
-
proposer = proposer_ctx.signer
|
|
822
|
-
confirmer = confirmer_ctx.signer
|
|
823
|
-
if proposer is None:
|
|
824
|
-
raise ValueError("proposer_ctx must have a signer")
|
|
825
|
-
if confirmer is None:
|
|
826
|
-
raise ValueError("confirmer_ctx must have a signer")
|
|
827
|
-
proposer_address = Web3.to_checksum_address(proposer)
|
|
828
|
-
if proposer_address == Web3.to_checksum_address(confirmer):
|
|
829
|
-
raise ValueError("proposer and confirmer must be different custodians")
|
|
830
|
-
if proposer_ctx.chain_id != confirmer_ctx.chain_id:
|
|
728
|
+
if found is None:
|
|
729
|
+
for_account = f" for account {wanted}" if wanted is not None else ""
|
|
831
730
|
raise ValueError(
|
|
832
|
-
f"
|
|
833
|
-
f"confirmer_ctx is on {confirmer_ctx.chain_id}; both custodians "
|
|
834
|
-
"must sign on the same chain"
|
|
731
|
+
f"no BalanceProposed log from executor {self._address}{for_account}"
|
|
835
732
|
)
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
proposal = self._last_balance_proposed(
|
|
843
|
-
propose_receipt["logs"], balance_account, confirmer_ctx.chain_id
|
|
844
|
-
)
|
|
845
|
-
if proposal is None:
|
|
846
|
-
raise ExternalStateError(
|
|
847
|
-
"the propose receipt records "
|
|
848
|
-
+ _no_balance_proposed(self._address, balance_account)
|
|
849
|
-
)
|
|
850
|
-
# The receipt is data from the node, so confirm only what we asked for:
|
|
851
|
-
# signing off on a proposal that differs from the one just sent would
|
|
852
|
-
# attest a value this call never chose.
|
|
853
|
-
if proposal.value != value:
|
|
854
|
-
raise ExternalStateError(
|
|
855
|
-
f"proposed {value} but the receipt records {proposal.value}; "
|
|
856
|
-
"refusing to confirm"
|
|
857
|
-
)
|
|
858
|
-
if proposal.proposer != proposer_address:
|
|
859
|
-
raise ExternalStateError(
|
|
860
|
-
f"proposal was made by {proposal.proposer}, not {proposer_address}; "
|
|
861
|
-
"refusing to confirm"
|
|
862
|
-
)
|
|
863
|
-
confirm_receipt = self.confirm_balance(
|
|
864
|
-
balance_account, proposal.proposal_hash
|
|
865
|
-
).send(confirmer_ctx)
|
|
866
|
-
|
|
867
|
-
refresh_receipt: TxReceipt | None = None
|
|
868
|
-
if vault is not None:
|
|
869
|
-
refresh_receipt = vault.update_markets_balances(
|
|
870
|
-
[MarketId(IporFusionMarkets.EXTERNAL_STATE)]
|
|
871
|
-
).send(confirmer_ctx)
|
|
872
|
-
|
|
873
|
-
return NavMark(
|
|
874
|
-
proposed_at=proposal.proposed_at,
|
|
875
|
-
nonce=proposal.nonce,
|
|
876
|
-
proposal_hash=proposal.proposal_hash,
|
|
877
|
-
propose_receipt=propose_receipt,
|
|
878
|
-
confirm_receipt=confirm_receipt,
|
|
879
|
-
refresh_receipt=refresh_receipt,
|
|
733
|
+
# Outside the loop: one hash instead of N, and only over the log
|
|
734
|
+
# actually being returned.
|
|
735
|
+
_require_matching_hash(
|
|
736
|
+
found,
|
|
737
|
+
executor=self._address,
|
|
738
|
+
chain_id=chain_id,
|
|
880
739
|
)
|
|
740
|
+
return found
|
|
@@ -212,10 +212,9 @@ class HyperCoreValuationError(IporFusionError, ValueError):
|
|
|
212
212
|
|
|
213
213
|
class ExternalStateError(IporFusionError, ValueError):
|
|
214
214
|
"""The external-state market's on-chain data is not usable: the vault's
|
|
215
|
-
storage holds no executor or a malformed word, an executor's
|
|
215
|
+
storage holds no executor or a malformed word, or an executor's
|
|
216
216
|
``BalanceProposed`` log is malformed or carries a hash that is not the hash
|
|
217
|
-
of its own fields
|
|
218
|
-
was sent.
|
|
217
|
+
of its own fields.
|
|
219
218
|
|
|
220
219
|
Also a ValueError, the type these failures had before 4.0.
|
|
221
220
|
"""
|