ipor-fusion 4.0.0.dev126__tar.gz → 4.0.0.dev137__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.dev137}/AGENTS.md +9 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/MIGRATION_4.md +65 -20
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/CONTRIBUTING.md +1 -5
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/advanced_euler_v2_credit_market_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/advanced_euler_v2_looping_arbitrum.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +8 -9
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +4 -5
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/external_state_margin_leg_base.py +4 -10
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/simple_aave_v3_supply_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/scripts/crosschain_readiness.py +5 -7
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/__init__.py +10 -6
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/market_cmd.py +9 -9
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/options.py +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_cmd.py +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/access.py +9 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/context.py +2 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/contract.py +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/external_state_executor.py +37 -172
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/multicall.py +1 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/oracle.py +5 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/plasma_vault.py +6 -5
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/__init__.py +8 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/__init__.py +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/chainlink.py +9 -8
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/codec.py +8 -8
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/contracts.py +5 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/indexer.py +1 -8
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/transport.py +3 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/fuses/ccip.py +2 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/lane.py +67 -5
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/dependency_graph.py +2 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/errors.py +21 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/explorer.py +2 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/__init__.py +2 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/external_state_events.py +1 -7
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/hypercore.py +2 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/market_info.py +6 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/mcp/server.py +10 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/hypercore.py +11 -9
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/hypercore_outcome.py +2 -5
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/unpriceable.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/substrates.py +2 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/types.py +2 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_data.py +6 -6
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_crosschain.py +1 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_crosschain_lifecycle.py +6 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_access_manager.py +14 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_commands.py +1 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_oracle_mapping.py +7 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_lane.py +110 -1
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_error_hierarchy.py +12 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_explorer.py +11 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_external_state_executor.py +10 -366
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_fuse_encoding.py +3 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_deployment.py +1 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_live.py +8 -6
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_outcome.py +1 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_readers.py +6 -6
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_simulation.py +0 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_mcp_server.py +7 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_public_api.py +10 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_borrow_aave_v3_mainnet.py +6 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_claim_merkl_wrapper_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_claim_morpho_rewards.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_crosschain_hypercore.py +1 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_crosschain_hyperevm.py +1 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_batch_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_credit_market_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_swap_deploy_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_swap_registry_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_external_state_executor_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_looping_aave_v3_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_looping_morpho_blue_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_morpho_blue.py +0 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_pilot_v3.py +12 -8
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_pilot_v4_uniswap.py +15 -10
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_pilot_v5_ramses.py +12 -8
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_pilot_v5_scheduled.py +18 -12
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_readers_integration.py +1 -3
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_release_funds.py +6 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_swap_on_base.py +6 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_vault_from_scratch_base.py +3 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_unpriceable_tokens.py +5 -5
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +1 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_web3_context.py +2 -4
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/typed_client/consumer.py +62 -2
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/typed_client/rejected.py +28 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/README.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/uv.lock +0 -0
|
@@ -186,7 +186,8 @@ the lifecycle matrix follows that.
|
|
|
186
186
|
|
|
187
187
|
## Layout (`src/ipor_fusion/`)
|
|
188
188
|
|
|
189
|
-
- `chains.py` chain registry; `market_ids.py` `IporFusionMarkets`; `types.py
|
|
189
|
+
- `chains.py` chain registry; `market_ids.py` `IporFusionMarkets`; `types.py`; `errors.py`
|
|
190
|
+
defines every SDK exception class (`tests/test_error_hierarchy.py` pins it)
|
|
190
191
|
- `about.py` — package version, repository URL, CHANGELOG parsing (`fusion changelog`,
|
|
191
192
|
`server_info`); `field_docs.py` — `DOCS`, the JSON field descriptions shared by CLI
|
|
192
193
|
output and MCP models
|
|
@@ -311,13 +312,18 @@ or examples.
|
|
|
311
312
|
that depends on another read) is named `read_*` and takes `ctx` first:
|
|
312
313
|
`PlasmaVault.read_balance_fuses(ctx)`, `AccessManager.read_all_role_accounts(ctx)`,
|
|
313
314
|
`MorphoReader.read_rates(ctx, id)`. Decide by the I/O a method performs, not
|
|
314
|
-
by the class name
|
|
315
|
+
by the class name; the prefix is reserved for that, so a method that builds
|
|
316
|
+
a `Call` offline (`PlasmaVault.universal_read`) or a pure helper
|
|
317
|
+
(`precompile_index_of`) never takes it. Resolvers that probe the chain to pick a wrapper
|
|
315
318
|
(`price_oracle_middleware(ctx, a)`, `resolve_access_manager`,
|
|
316
319
|
`ExternalStateExecutor.for_vault`) return context-free wrappers. Executors
|
|
317
320
|
and orchestrators own their contexts: `Multicall3(ctx)`, `VaultSimulator`,
|
|
318
321
|
`CrosschainSimulator`, `OracleMappingReader(ctx, oracle)` and
|
|
319
322
|
`CrosschainLane` (`hub_ctx` for the executor, `spoke_ctx` for the
|
|
320
|
-
dispatcher at the same address
|
|
323
|
+
dispatcher at the same address; its eager `read_hub_state()` and
|
|
324
|
+
`read_observation()` run on the right one, and its Calls on whichever the
|
|
325
|
+
caller picks). A context is pinned by copy, `ctx.at_block(n)`;
|
|
326
|
+
`default_block` is read-only.
|
|
321
327
|
A chain-dependent decode takes the chain explicitly
|
|
322
328
|
(`ExternalStateExecutor.pending_proposals(account, chain_id=)`); a decoder
|
|
323
329
|
never consults the executing context.
|
|
@@ -33,7 +33,7 @@ values; they do not validate byte widths or address spelling.
|
|
|
33
33
|
| `MorphoBlueMarketId` | `parse_morpho_market_id(value)`: 32 bytes or hex in any spelling, always `0x` + 64 lowercase digits |
|
|
34
34
|
| `TxHash` | `parse_tx_hash(value)` (32 bytes or `0x`/`0X`-prefixed hex in any case) |
|
|
35
35
|
| `PlasmaVaultAddress`, `FuseAddress`, `AccessManagerAddress` | from the SDK (`PlasmaVault.address`, `get_fuses()`, `get_access_manager_address()`, `FusionInstance`, discovery), or `parse_plasma_vault_address` / `parse_fuse_address` / `parse_access_manager_address(value)` for a raw address; they label the role and check nothing on chain |
|
|
36
|
-
| crosschain ids | `CommandId(b)`, `MessageId(b)`, `AssetId(b)`, `OperationId(b)`, `TransferId(b)`, `ReturnRequestId(b)`, `PositionSetHash(b)` (bytes32); `ProposalId(n)`, `DeploymentRequestId(n)`, `StargateAssetId(n)` (int) |
|
|
36
|
+
| crosschain ids | `CommandId(b)`, `MessageId(b)`, `AssetId(b)`, `OperationId(b)`, `TransferId(b)`, `ReturnRequestId(b)`, `PositionSetHash(b)` (bytes32); `ProposalId(n)`, `DeploymentRequestId(n)`, `StargateAssetId(n)`, `LayerZeroEid(n)`, `CcipChainSelector(n)` (int) |
|
|
37
37
|
| HyperCore ids | `HyperCoreTokenIndex(n)` (or `USDC_TOKEN_INDEX`), `HyperCoreAsset(n)` (or `hip3_action_asset(dex, index)`), `HyperCoreOrderId(n)`, `HyperCoreClientOrderId(n)`, `MarginTableId(n)`, `HyperCoreActionId(n)`, `PayloadHash(b)` |
|
|
38
38
|
| external state | `ProposalHash(b)` |
|
|
39
39
|
| `BlockIdentifier` | a block number, `"latest"` / `"pending"` / ..., or a block hash |
|
|
@@ -92,6 +92,9 @@ chain is always the context's:
|
|
|
92
92
|
`Call.call(ctx, *, block=None)` (see [Context-free wrappers](#context-free-wrappers)). `Web3Context.get_logs(to_block=None)` ends at
|
|
93
93
|
the context's default block and `Web3Context.get_block(block=None)` returns it,
|
|
94
94
|
both instead of ``"latest"``.
|
|
95
|
+
- `Web3Context.default_block` is read-only: `ctx.default_block = n` raises
|
|
96
|
+
`AttributeError`. Pin a copy instead, `ctx = ctx.at_block(n)`; the old setter
|
|
97
|
+
changed the block under every thread sharing the context.
|
|
95
98
|
|
|
96
99
|
Snapshot fields carry their units: `VaultData.total_assets`,
|
|
97
100
|
`underlying_balance_on_vault` and `market_balances` values are `Amount`;
|
|
@@ -122,15 +125,21 @@ context built with it shares the same `n` slots. A context built from your own
|
|
|
122
125
|
`limit.install(web3)` (innermost, as `from_url` does) or
|
|
123
126
|
`web3.middleware_onion.inject(limit.middleware, layer=0)`.
|
|
124
127
|
|
|
125
|
-
`ensure_supported_chain` takes `ChainId`. `fetch_unpriceable_priced_tokens
|
|
126
|
-
underlying
|
|
128
|
+
`ensure_supported_chain` takes `ChainId`. `fetch_unpriceable_priced_tokens(ctx, *,
|
|
129
|
+
price_oracle, underlying, balance_fuses, market_substrates, morpho_positions)` takes
|
|
130
|
+
everything after `ctx` by keyword, the oracle and underlying as `ChecksumAddress`.
|
|
131
|
+
`resolve_token_symbol`, `resolve_token_decimals`,
|
|
127
132
|
`get_contract_name` and `get_deployment_tx` take `HexAddress` (a checksum address
|
|
128
|
-
fits)
|
|
133
|
+
fits) and `api_key` by keyword only (`get_contract_name(chain_id, address, *,
|
|
134
|
+
api_key=None, cache=None)`, `get_deployment_tx(chain_id, address, *, api_key=None)`),
|
|
135
|
+
and the `resolve_name` / `resolve_symbol` callbacks receive one (a callback
|
|
129
136
|
typed for `str` still fits). Market-keyed data is keyed by `MarketId`:
|
|
130
137
|
`VaultData.market_substrates`, `dependency_graph`, `morpho_positions`,
|
|
131
138
|
`aave_positions`, `market_balances`; the `VaultState` protocol, `fetch_vault_lending_health`, `fetch_unpriceable_priced_tokens`
|
|
132
139
|
and the `dependency_graph` helpers (`compute_update_reach`, `compute_update_groups`,
|
|
133
140
|
`find_orphan_fuse_markets`, `find_markets_missing_erc20_dependency`).
|
|
141
|
+
`find_orphan_fuse_markets` returns `dict[MarketId, list[FuseAddress]]`, so its
|
|
142
|
+
fuses go into `PlasmaVault.remove_fuses` as they are.
|
|
134
143
|
|
|
135
144
|
`VaultData.price_oracle_addr` is renamed `price_oracle`, like its sibling
|
|
136
145
|
address fields (a custom `VaultState` renames it too).
|
|
@@ -148,7 +157,8 @@ The Uniswap V3 / Ramses V2 position events' `version`, `sender` and `recipient`
|
|
|
148
157
|
`LendingMarketHealth.market_id` and `MiddlewarePricedToken.market_id` are
|
|
149
158
|
`MarketId`; `Erc20Holding.address` is `HexAddress`, and `SubstrateInfo.address` is
|
|
150
159
|
`HexAddress | None` (`None`, no longer `""`, when a substrate carries no address).
|
|
151
|
-
`LegacyPriceOracleMiddleware` takes `base_currency_decimals: Decimals
|
|
160
|
+
`LegacyPriceOracleMiddleware` takes `base_currency_decimals: Decimals`, and
|
|
161
|
+
`PriceOracleMiddleware.base_currency_decimals()` returns `Call[Decimals]`.
|
|
152
162
|
`get_logs_adaptive(chain_id=)` and `LogSource.get_logs` take `ChainId`;
|
|
153
163
|
`quote_ccip_native_fee(block=)` and `OracleMappingReader.asset_source_events` take a
|
|
154
164
|
`BlockIdentifier`.
|
|
@@ -167,7 +177,9 @@ the async command helpers `Command.request_shares` / `redeem_from_request`,
|
|
|
167
177
|
Every fuse constructor, `FuseAction.fuse`, `BalanceFuse.fuse`,
|
|
168
178
|
`PlasmaVault.add_fuses` / `remove_fuses` / `add_balance_fuse` / `remove_balance_fuse`
|
|
169
179
|
/ `balance_fuse_value`, `RewardsManager.add_reward_fuses` / `is_reward_fuse_supported`,
|
|
170
|
-
`LaneFuses
|
|
180
|
+
`LaneFuses`, the HyperCore balance-fuse argument and the
|
|
181
|
+
`PlasmaVault.configure_instant_withdrawal_fuses` configs
|
|
182
|
+
(`Sequence[tuple[FuseAddress, Sequence[bytes]]]`) take a `FuseAddress`, and
|
|
171
183
|
`get_fuses()`, `get_instant_withdrawal_fuses()`, `get_rewards_fuses()` and
|
|
172
184
|
`VaultData.fuses` / `instant_fuses` / `fuse_markets` keys return it.
|
|
173
185
|
`AccessManager(address)` takes an `AccessManagerAddress`;
|
|
@@ -196,7 +208,13 @@ from_=...)` needs neither, so drop a zero-address placeholder. `execute()` witho
|
|
|
196
208
|
the fee fields are `Wei`). LayerZero endpoint ids are `LayerZeroEid`:
|
|
197
209
|
`StargateChain.eid`, `Packet.src_eid` / `dst_eid`, `EnforcedOptionParam.eid`,
|
|
198
210
|
`executor_eid()` and `eid_of()` return it and `chain_id_of`, `peers`, `lz_receive_calldata(src_eid=)`
|
|
199
|
-
and the Stargate fuse's `eid=` take it (`LayerZeroEid(30101)`).
|
|
211
|
+
and the Stargate fuse's `eid=` take it (`LayerZeroEid(30101)`). CCIP chain
|
|
212
|
+
selectors are `CcipChainSelector`: `CcipChain.chain_selector`,
|
|
213
|
+
`CcipRouteConfig.chain_selector`, `CcipTokenLane.chain_selector`, the `MessageV1`,
|
|
214
|
+
`CcipMessageSent` and `Any2EVMMessage` selectors and `CcipRouter.get_off_ramps()`
|
|
215
|
+
carry it, and `chain_id_of_selector`, `CcipRouter.is_chain_supported` /
|
|
216
|
+
`get_on_ramp`, `CcipTokenPool.is_supported_chain` and `ccip_token_lane` take it
|
|
217
|
+
(`CcipChainSelector(4949039107694359620)`).
|
|
200
218
|
`encode_oft_compose_msg(*, nonce=, src_eid=, amount_ld=, compose_msg=)` takes
|
|
201
219
|
keyword arguments only. `ZERO_ADDRESS` is a `ChecksumAddress` (same value).
|
|
202
220
|
|
|
@@ -229,7 +247,10 @@ gone: use `morpho_blue_address(chain_id)`.
|
|
|
229
247
|
`MorphoPositionBreakdown.market_id` (as read from substrates) and the keys of
|
|
230
248
|
`VaultV1Info.public_allocator_flow_caps` are canonical. `fetch_market`, `fetch_vault`,
|
|
231
249
|
`morpho_blue_address`, `build_*_json` take `ChainId`; `fetch_vault` takes a
|
|
232
|
-
`ChecksumAddress`.
|
|
250
|
+
`ChecksumAddress`. `build_morpho_blue_market_json(*, market_id, chain_id, params,
|
|
251
|
+
state, rates, api_market=None, api_error=None, public_allocator=None)` takes every
|
|
252
|
+
argument by keyword, `public_allocator` as `ChecksumAddress | None`.
|
|
253
|
+
Every address on the `morpho_api` records is `ChecksumAddress`;
|
|
233
254
|
optional ones (`curator`, `guardian`, `fee_recipient`, `performance_fee_recipient`,
|
|
234
255
|
`management_fee_recipient`, `inner_vault`, `VaultFlowCap.admin`, the `VaultV2Cap`
|
|
235
256
|
market params) are `ChecksumAddress | None`.
|
|
@@ -249,14 +270,24 @@ on CCIP, `active_return` → `OperationId`, `asset_id`, `tracked_position_set_ha
|
|
|
249
270
|
before passing it on.
|
|
250
271
|
|
|
251
272
|
**HyperCore (preview).** The fuses, `HyperCoreSubstrates`, `HyperCoreReader`,
|
|
252
|
-
`read_hypercore_transfer_snapshot` and the helpers `system_address`, `
|
|
273
|
+
`read_hypercore_transfer_snapshot` and the helpers `system_address`, `precompile_index_of`
|
|
274
|
+
(3.x `read_index_of`, renamed: it reads nothing),
|
|
253
275
|
`perp_dex_of`, `is_native_perp_asset`, `is_hip3_asset` take the HyperCore ids;
|
|
254
276
|
`HyperCorePerpAssetInfo`, `HyperCorePerpMarket`, `HyperCoreSpotLeg`,
|
|
255
277
|
`HyperCorePendingState` and `HyperCoreTransferSnapshot` carry them.
|
|
278
|
+
`HyperCorePendingReader(vault, reader)` takes the vault's `PlasmaVaultAddress`, not a
|
|
279
|
+
`PlasmaVault` wrapper.
|
|
256
280
|
|
|
257
281
|
**External state.** `ExternalStateExecutor.proposal_hash` returns and `confirm_balance`
|
|
258
|
-
takes a `ProposalHash`; `BalanceProposal.proposal_hash`
|
|
259
|
-
|
|
282
|
+
takes a `ProposalHash`; `BalanceProposal.proposal_hash` is a `ProposalHash`;
|
|
283
|
+
`ExternalStateEvent.transaction_hash` is a `TxHash`.
|
|
284
|
+
`ExternalStateVaultState.last_checked_custodian_timestamp`,
|
|
285
|
+
`BalanceFuseSnapshot.last_custodian_update_timestamp`, `BalanceProposal.proposed_at`,
|
|
286
|
+
`last_updated()` and `get_oldest_update_timestamp()` are web3's `Timestamp`, and
|
|
287
|
+
`ExternalStateExecutor.proposal_hash(proposed_at=)` takes one.
|
|
288
|
+
`ExternalStateExecutor.mark_nav` and `NavMark` are gone: send `propose_balance` and
|
|
289
|
+
`confirm_balance` from separate custodians, then
|
|
290
|
+
`PlasmaVault.update_markets_balances([IporFusionMarkets.EXTERNAL_STATE])`.
|
|
260
291
|
|
|
261
292
|
**Errors and explorer.** `TransactionError(tx_hash=)` takes a `TxHash`,
|
|
262
293
|
`LogScanError(address=)` a `ChecksumAddress`; `get_revert_reason` takes a `TxHash`;
|
|
@@ -324,7 +355,8 @@ placeholder wrapper.
|
|
|
324
355
|
`.decode(raw)` and `.map(f)` need no context. `Call(...)` no longer takes `ctx=`.
|
|
325
356
|
- A wrapper method that executes to answer (storage, log scans, dependent reads) is
|
|
326
357
|
named `read_*` and takes the context first (table below).
|
|
327
|
-
- Executors and orchestrators keep their contexts: `Multicall3(ctx
|
|
358
|
+
- Executors and orchestrators keep their contexts: `Multicall3(ctx, *, address=,
|
|
359
|
+
batch_size=)` (options by keyword; every batch,
|
|
328
360
|
every re-run of a failed sub-call and the per-call fallback run on its `ctx`, so a
|
|
329
361
|
pinned context keeps them all at its block; it is no longer a `ContractWrapper`,
|
|
330
362
|
`aggregate3(calls)` still returns the raw `Call`), `VaultSimulator`,
|
|
@@ -339,7 +371,14 @@ placeholder wrapper.
|
|
|
339
371
|
`command_in_flight` and `transfer_in_flight` read on `hub_ctx`. The Calls a lane
|
|
340
372
|
returns are unexecuted, and the executor and dispatcher share one address, so pick
|
|
341
373
|
the context yourself: `lane.get_balance().call(lane.hub_ctx)`,
|
|
342
|
-
`lane.observation().call(lane.spoke_ctx)
|
|
374
|
+
`lane.observation().call(lane.spoke_ctx)`, or let the lane pick:
|
|
375
|
+
`lane.read_hub_state()` reads every executor bucket and counter
|
|
376
|
+
(`LaneHubState`) on `hub_ctx` through `Multicall3`, at one block (a `latest`, `safe` or
|
|
377
|
+
`finalized` default block resolved to its number once, so a per-call fallback
|
|
378
|
+
stays on it; a number or hash as is);
|
|
379
|
+
`lane.read_observation()` runs the observation on `spoke_ctx`. Keep
|
|
380
|
+
`transfer_in_flight()` / `command_in_flight()` for those decisions: the counters
|
|
381
|
+
do not see a CCIP recall or tell a parked command from a pending one. `CrosschainTransport.executor(address)`
|
|
343
382
|
and `.dispatcher(address)` no longer take a context.
|
|
344
383
|
- Chain-bound decoding takes the chain explicitly:
|
|
345
384
|
`ExternalStateExecutor.pending_proposals(account, *, chain_id)`,
|
|
@@ -349,7 +388,7 @@ placeholder wrapper.
|
|
|
349
388
|
and `VaultSimulator.observe` stamp the same hash for the same bytes, whatever
|
|
350
389
|
context executes them. Pass `ctx.chain_id` for the chain you read from.
|
|
351
390
|
`pending_proposals` now refuses an executor at the zero address when the Call is
|
|
352
|
-
built, not when it is decoded.
|
|
391
|
+
built, not when it is decoded.
|
|
353
392
|
|
|
354
393
|
| 3.x | 4.0 |
|
|
355
394
|
|---|---|
|
|
@@ -377,6 +416,10 @@ placeholder wrapper.
|
|
|
377
416
|
| `MorphoReader.rates_from(market, params)` | `MorphoReader.read_rates_from(ctx, market, params)` (it reads the IRM) |
|
|
378
417
|
| `AaveV3Reader.position_breakdown(asset, user)` | `AaveV3Reader.read_position_breakdown(ctx, asset, user)` |
|
|
379
418
|
| `AaveV3FuseReader.pool()` | `AaveV3FuseReader.read_pool(ctx)` |
|
|
419
|
+
| `PlasmaVault.read(target, data)` / `read_as(target, data, ...)` | `PlasmaVault.universal_read(target, data)` / `universal_read_decoded(target, data, ...)` (they build a Call; `read_*` names only methods that execute) |
|
|
420
|
+
| `read_index_of(asset)` | `precompile_index_of(asset)` |
|
|
421
|
+
| `ctx.default_block = n` | `ctx = ctx.at_block(n)` |
|
|
422
|
+
| `Multicall3(ctx, address)` | `Multicall3(ctx, address=address)` |
|
|
380
423
|
| `executor.pending_proposals(account)` | `executor.pending_proposals(account, chain_id=ctx.chain_id)` |
|
|
381
424
|
| `executor.parse_balance_proposed(log)` / `find_balance_proposed(logs)` | `...(log, chain_id=...)` / `...(logs, chain_id=...)` |
|
|
382
425
|
| `CcipLane(executor=, dispatcher=, spoke_chain_id=, ...)` | `CcipLane(hub_ctx=, spoke_ctx=, executor=, dispatcher=, ...)` (same for `StargateLane`) |
|
|
@@ -509,8 +552,12 @@ is the wrong one.
|
|
|
509
552
|
- `MorphoApiError` (still a `RuntimeError`), `ExternalStateEventDecodeError` (still a
|
|
510
553
|
`ValueError`) and `VerifierResultUnavailable` (still a `LookupError`) now derive
|
|
511
554
|
from `IporFusionError`, so an `except IporFusionError` placed before their own
|
|
512
|
-
handlers catches them first.
|
|
513
|
-
exported from `ipor_fusion`;
|
|
555
|
+
handlers catches them first. All three live in `ipor_fusion.errors`, like every
|
|
556
|
+
other SDK exception, and are exported from `ipor_fusion`; the modules that raise
|
|
557
|
+
them (`ipor_fusion.morpho_api`, `ipor_fusion.fuses.external_state_events`,
|
|
558
|
+
`ipor_fusion.crosschain.ccip.indexer`) still import the same classes.
|
|
559
|
+
- `AccessManager.read_owner(ctx)` raises the new `OwnerNotFoundError` (a
|
|
560
|
+
`LookupError`) when no account holds `OWNER_ROLE`, instead of an `IndexError`.
|
|
514
561
|
- `EmptyCallResultError` is no longer an eth_abi `InsufficientDataBytes` (nor a
|
|
515
562
|
`DecodingError`). Code that caught either around `.call()` to tolerate a missing
|
|
516
563
|
contract or getter must catch `EmptyCallResultError`; return data that is present
|
|
@@ -560,10 +607,8 @@ is the wrong one.
|
|
|
560
607
|
`parse_balance_proposed` / `find_balance_proposed` for one of the executor's own
|
|
561
608
|
`BalanceProposed` logs whose data is missing or malformed (including data that is
|
|
562
609
|
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`.
|
|
610
|
+
fields. A log that is not the event or not from the executor, and
|
|
611
|
+
`find_balance_proposed` over logs that hold no match, are still `ValueError`.
|
|
567
612
|
- `ccip_token_lane` raises the new `UnsupportedContractVersionError` (still a
|
|
568
613
|
`ValueError`) for an OnRamp version whose layout is not verified.
|
|
569
614
|
- `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
|
|
|
@@ -367,8 +367,9 @@ def withdraw_collateral_action(max_amount: Amount) -> FuseAction:
|
|
|
367
367
|
|
|
368
368
|
def run_simulation(web3: Web3) -> SimulationResult:
|
|
369
369
|
"""Build, fund and run the full Euler V2 credit lifecycle in one batch."""
|
|
370
|
-
ctx = Web3Context(web3=web3, chain_id=BASE_CHAIN_ID, signer=OWNER)
|
|
371
|
-
|
|
370
|
+
ctx = Web3Context(web3=web3, chain_id=BASE_CHAIN_ID, signer=OWNER).at_block(
|
|
371
|
+
PINNED_BLOCK
|
|
372
|
+
)
|
|
372
373
|
factory = FusionFactory(BASE_FUSION_FACTORY)
|
|
373
374
|
|
|
374
375
|
# 1. Preview the deterministic addresses (eth_call, no gas, no state change).
|
{ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/advanced_euler_v2_looping_arbitrum.py
RENAMED
|
@@ -315,8 +315,9 @@ def build_loop_action() -> FuseAction:
|
|
|
315
315
|
|
|
316
316
|
def run_simulation(web3: Web3) -> SimulationResult:
|
|
317
317
|
"""Build, configure and run the WBTC/USDC leveraged loop without broadcasting."""
|
|
318
|
-
ctx = Web3Context(web3=web3, chain_id=ARBITRUM_CHAIN_ID, signer=OWNER)
|
|
319
|
-
|
|
318
|
+
ctx = Web3Context(web3=web3, chain_id=ARBITRUM_CHAIN_ID, signer=OWNER).at_block(
|
|
319
|
+
PINNED_BLOCK
|
|
320
|
+
)
|
|
320
321
|
factory = FusionFactory(ARBITRUM_FUSION_FACTORY)
|
|
321
322
|
preview = factory.clone(**clone_args()).call(ctx)
|
|
322
323
|
|
|
@@ -76,6 +76,7 @@ from ipor_fusion import (
|
|
|
76
76
|
USDC_SYSTEM_ADDRESS,
|
|
77
77
|
USDC_TOKEN_INDEX,
|
|
78
78
|
CcipChain,
|
|
79
|
+
CcipChainSelector,
|
|
79
80
|
CcipCrosschainExecutor,
|
|
80
81
|
CcipTransport,
|
|
81
82
|
Command,
|
|
@@ -94,10 +95,10 @@ from ipor_fusion import (
|
|
|
94
95
|
open_lane,
|
|
95
96
|
parse_fuse_address,
|
|
96
97
|
parse_plasma_vault_address,
|
|
98
|
+
precompile_index_of,
|
|
97
99
|
quote_ccip_native_fee,
|
|
98
100
|
read_hypercore_evm_exit_ceiling,
|
|
99
101
|
read_hypercore_vault_state,
|
|
100
|
-
read_index_of,
|
|
101
102
|
register_custom_errors,
|
|
102
103
|
)
|
|
103
104
|
from ipor_fusion.fuses import (
|
|
@@ -133,8 +134,8 @@ register_custom_errors(HYPERCORE_SEND_FUSE_ERRORS)
|
|
|
133
134
|
ARBITRUM_CHAIN_ID = ChainId(42161)
|
|
134
135
|
HYPEREVM_CHAIN_ID = ChainId(999)
|
|
135
136
|
# Chainlink CCIP routers and chain selectors (docs.chain.link -> CCIP -> Directory).
|
|
136
|
-
ARBITRUM_CCIP_SELECTOR = 4949039107694359620
|
|
137
|
-
HYPEREVM_CCIP_SELECTOR = 2442541497099098535
|
|
137
|
+
ARBITRUM_CCIP_SELECTOR = CcipChainSelector(4949039107694359620)
|
|
138
|
+
HYPEREVM_CCIP_SELECTOR = CcipChainSelector(2442541497099098535)
|
|
138
139
|
ARBITRUM_CCIP_ROUTER = Web3.to_checksum_address(
|
|
139
140
|
"0x141fa059441E0ca23ce184B6A78bafD2A517DdE8"
|
|
140
141
|
)
|
|
@@ -428,7 +429,7 @@ def core_leg_previews(web3_hype: Web3) -> list[Preview]:
|
|
|
428
429
|
xyz_equity_usd6 = int(
|
|
429
430
|
reader.account_margin_summary(XYZ_DEX, HYPERCORE_VAULT).call(ctx).account_value
|
|
430
431
|
)
|
|
431
|
-
read_index =
|
|
432
|
+
read_index = precompile_index_of(XYZ_NVDA_ASSET)
|
|
432
433
|
# The precompile quotes a perp price with ``6 - szDecimals`` decimals; the
|
|
433
434
|
# order fuse takes 8 implied decimals. Read szDecimals, then rescale.
|
|
434
435
|
sz_decimals = int(reader.perp_asset_info(read_index).call(ctx).sz_decimals)
|
|
@@ -662,9 +663,7 @@ def _transport() -> CcipTransport:
|
|
|
662
663
|
|
|
663
664
|
|
|
664
665
|
def _pinned(web3: Web3, chain_id: ChainId, block: int) -> Web3Context:
|
|
665
|
-
|
|
666
|
-
ctx.default_block = block
|
|
667
|
-
return ctx
|
|
666
|
+
return Web3Context(web3, chain_id=chain_id).at_block(block)
|
|
668
667
|
|
|
669
668
|
|
|
670
669
|
class _Tail(NamedTuple):
|
|
@@ -889,8 +888,8 @@ def recall_attest_claim(web3_arb: Web3, web3_hype: Web3) -> dict[str, int]:
|
|
|
889
888
|
|
|
890
889
|
# Where the live cycle stood: the settled bucket carries attestation 8, the
|
|
891
890
|
# dispatcher holds the redeemed idle and the residual shares.
|
|
892
|
-
settled_before = int(lane.
|
|
893
|
-
observation_before = lane.
|
|
891
|
+
settled_before = int(lane.read_hub_state().settled_remote_balance)
|
|
892
|
+
observation_before = lane.read_observation()
|
|
894
893
|
remote_idle = Amount(int(observation_before.tracked_idle))
|
|
895
894
|
residual_shares = int(
|
|
896
895
|
PlasmaVault(HYPERCORE_VAULT).balance_of(EXECUTOR).call(spoke_ctx)
|
|
@@ -70,6 +70,7 @@ from web3 import Web3
|
|
|
70
70
|
from ipor_fusion import (
|
|
71
71
|
ERC20,
|
|
72
72
|
CcipChain,
|
|
73
|
+
CcipChainSelector,
|
|
73
74
|
CcipTransport,
|
|
74
75
|
Command,
|
|
75
76
|
CrosschainLane,
|
|
@@ -93,8 +94,8 @@ log = logging.getLogger("crosschain_ccip_usdc_arbitrum_hyperevm")
|
|
|
93
94
|
# (docs.chain.link -> CCIP -> Directory -> Arbitrum One / Hyperliquid).
|
|
94
95
|
ARBITRUM_CHAIN_ID = ChainId(42161)
|
|
95
96
|
HYPEREVM_CHAIN_ID = ChainId(999)
|
|
96
|
-
ARBITRUM_CCIP_SELECTOR = 4949039107694359620
|
|
97
|
-
HYPEREVM_CCIP_SELECTOR = 2442541497099098535
|
|
97
|
+
ARBITRUM_CCIP_SELECTOR = CcipChainSelector(4949039107694359620)
|
|
98
|
+
HYPEREVM_CCIP_SELECTOR = CcipChainSelector(2442541497099098535)
|
|
98
99
|
ARBITRUM_CCIP_ROUTER = Web3.to_checksum_address(
|
|
99
100
|
"0x141fa059441E0ca23ce184B6A78bafD2A517DdE8"
|
|
100
101
|
)
|
|
@@ -205,9 +206,7 @@ def _connected_web3(env_var: str, chain_id: ChainId) -> Web3:
|
|
|
205
206
|
|
|
206
207
|
|
|
207
208
|
def _pinned_context(web3: Web3, chain_id: ChainId, block: int) -> Web3Context:
|
|
208
|
-
|
|
209
|
-
ctx.default_block = block
|
|
210
|
-
return ctx
|
|
209
|
+
return Web3Context(web3, chain_id=chain_id).at_block(block)
|
|
211
210
|
|
|
212
211
|
|
|
213
212
|
# ── Pure builders (no chain access, unit-testable offline) ───────────────────
|
{ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/external_state_margin_leg_base.py
RENAMED
|
@@ -807,8 +807,9 @@ def run_simulation(web3: Web3) -> SimulationResult:
|
|
|
807
807
|
function does (exactly one failure, with the expected revert selector), not
|
|
808
808
|
with ``result.all_success``.
|
|
809
809
|
"""
|
|
810
|
-
ctx = Web3Context(web3=web3, chain_id=BASE_CHAIN_ID, signer=OWNER)
|
|
811
|
-
|
|
810
|
+
ctx = Web3Context(web3=web3, chain_id=BASE_CHAIN_ID, signer=OWNER).at_block(
|
|
811
|
+
PINNED_BLOCK
|
|
812
|
+
)
|
|
812
813
|
|
|
813
814
|
factory = FusionFactory(BASE_FUSION_FACTORY)
|
|
814
815
|
|
|
@@ -894,13 +895,6 @@ def run_simulation(web3: Web3) -> SimulationResult:
|
|
|
894
895
|
# driven from this one process. In a real deployment they live in separate
|
|
895
896
|
# systems -- if one process can send both, a single compromise moves the
|
|
896
897
|
# 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
898
|
sim.next_block().with_block_time_shift(PROPOSE_OFFSET)
|
|
905
899
|
sim.add_call(
|
|
906
900
|
call=executor.propose_balance(VENUE_BALANCE_ACCOUNT, MARGIN_AMOUNT),
|
|
@@ -938,7 +932,7 @@ def run_simulation(web3: Web3) -> SimulationResult:
|
|
|
938
932
|
# to one custodian by either route, however separate the two keys are -- and
|
|
939
933
|
# that is why a production deployment cannot drive both halves from one
|
|
940
934
|
# process, whatever this example does under simulation.
|
|
941
|
-
proposed_at = baseline_timestamp + PROPOSE_OFFSET
|
|
935
|
+
proposed_at = Timestamp(baseline_timestamp + PROPOSE_OFFSET)
|
|
942
936
|
proposal_hash = ExternalStateExecutor.proposal_hash(
|
|
943
937
|
executor=executor_address,
|
|
944
938
|
chain_id=BASE_CHAIN_ID,
|
{ipor_fusion-4.0.0.dev126 → ipor_fusion-4.0.0.dev137}/examples/simple_aave_v3_supply_base.py
RENAMED
|
@@ -225,8 +225,9 @@ def build_supply_action(amount: Amount) -> FuseAction:
|
|
|
225
225
|
|
|
226
226
|
def run_simulation(web3: Web3) -> SimulationResult:
|
|
227
227
|
"""Build, fund, deposit and supply -- all in one eth_simulateV1 batch."""
|
|
228
|
-
ctx = Web3Context(web3=web3, chain_id=BASE_CHAIN_ID, signer=OWNER)
|
|
229
|
-
|
|
228
|
+
ctx = Web3Context(web3=web3, chain_id=BASE_CHAIN_ID, signer=OWNER).at_block(
|
|
229
|
+
PINNED_BLOCK
|
|
230
|
+
)
|
|
230
231
|
factory = FusionFactory(BASE_FUSION_FACTORY)
|
|
231
232
|
|
|
232
233
|
# 1. Preview the deterministic addresses (eth_call, no gas, no state change).
|
|
@@ -43,7 +43,7 @@ from web3.types import RPCEndpoint
|
|
|
43
43
|
|
|
44
44
|
from ipor_fusion import ERC20, Call, Web3Context, ccip_token_lane
|
|
45
45
|
from ipor_fusion.crosschain import CcipCrosschainFactory, CcipOffRamp, CcipRouter
|
|
46
|
-
from ipor_fusion.types import ChainId
|
|
46
|
+
from ipor_fusion.types import CcipChainSelector, ChainId
|
|
47
47
|
|
|
48
48
|
SCHEMA = "ipor-fusion.crosschain-readiness/4"
|
|
49
49
|
EXIT_OK = 0
|
|
@@ -126,7 +126,7 @@ class ChainSpec:
|
|
|
126
126
|
|
|
127
127
|
name: str
|
|
128
128
|
chain_id: ChainId
|
|
129
|
-
chain_selector:
|
|
129
|
+
chain_selector: CcipChainSelector
|
|
130
130
|
env_var: str
|
|
131
131
|
router: ChecksumAddress
|
|
132
132
|
usdc: ChecksumAddress
|
|
@@ -137,7 +137,7 @@ class ChainSpec:
|
|
|
137
137
|
ARBITRUM = ChainSpec(
|
|
138
138
|
name="arbitrum",
|
|
139
139
|
chain_id=ChainId(42161),
|
|
140
|
-
chain_selector=4949039107694359620,
|
|
140
|
+
chain_selector=CcipChainSelector(4949039107694359620),
|
|
141
141
|
env_var="ARBITRUM_PROVIDER_URL",
|
|
142
142
|
router=Web3.to_checksum_address("0x141fa059441E0ca23ce184B6A78bafD2A517DdE8"),
|
|
143
143
|
usdc=Web3.to_checksum_address("0xaf88d065e77c8cC2239327C5EDb3A432268e5831"),
|
|
@@ -150,7 +150,7 @@ ARBITRUM = ChainSpec(
|
|
|
150
150
|
HYPEREVM = ChainSpec(
|
|
151
151
|
name="hyperevm",
|
|
152
152
|
chain_id=ChainId(999),
|
|
153
|
-
chain_selector=2442541497099098535,
|
|
153
|
+
chain_selector=CcipChainSelector(2442541497099098535),
|
|
154
154
|
env_var="HYPEREVM_PROVIDER_URL",
|
|
155
155
|
router=Web3.to_checksum_address("0x13b3332b66389B1467CA6eBd6fa79775CCeF65ec"),
|
|
156
156
|
usdc=Web3.to_checksum_address("0xb88339CB7199b77E23DB6E890353E22632Ba630f"),
|
|
@@ -756,9 +756,7 @@ def connect(spec: ChainSpec) -> Web3Context:
|
|
|
756
756
|
raise ReadinessConfigError(
|
|
757
757
|
f"{spec.env_var}: chain id {chain_id}, expected {spec.chain_id}"
|
|
758
758
|
)
|
|
759
|
-
|
|
760
|
-
ctx.default_block = head
|
|
761
|
-
return ctx
|
|
759
|
+
return Web3Context(web3=web3, chain_id=spec.chain_id).at_block(head)
|
|
762
760
|
|
|
763
761
|
|
|
764
762
|
def config_error_report(message: str) -> dict[str, Any]:
|
|
@@ -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
|
)
|
|
@@ -145,6 +144,7 @@ from ipor_fusion.crosschain import (
|
|
|
145
144
|
EVMTokenAmount,
|
|
146
145
|
ExecutorInitParams,
|
|
147
146
|
LaneFuses,
|
|
147
|
+
LaneHubState,
|
|
148
148
|
LaneObservation,
|
|
149
149
|
MessageExecutionState,
|
|
150
150
|
MessageV1,
|
|
@@ -169,7 +169,6 @@ from ipor_fusion.crosschain import (
|
|
|
169
169
|
TaxiMessage,
|
|
170
170
|
TokenTransferV1,
|
|
171
171
|
VerifierResult,
|
|
172
|
-
VerifierResultUnavailable,
|
|
173
172
|
ccip_events,
|
|
174
173
|
ccip_receive_calldata,
|
|
175
174
|
ccip_token_lane,
|
|
@@ -206,18 +205,21 @@ from ipor_fusion.errors import (
|
|
|
206
205
|
CrosschainDiscoveryError,
|
|
207
206
|
EmptyCallResultError,
|
|
208
207
|
ExternalStateError,
|
|
208
|
+
ExternalStateEventDecodeError,
|
|
209
209
|
HyperCoreValuationError,
|
|
210
210
|
IporFusionError,
|
|
211
211
|
LogScanError,
|
|
212
212
|
LogSourceUnavailable,
|
|
213
213
|
MorphoMarketNotFoundError,
|
|
214
214
|
NotPlasmaVaultError,
|
|
215
|
+
OwnerNotFoundError,
|
|
215
216
|
SimulationError,
|
|
216
217
|
SimulationRunError,
|
|
217
218
|
TransactionError,
|
|
218
219
|
UnsupportedChainError,
|
|
219
220
|
UnsupportedContractVersionError,
|
|
220
221
|
UnsupportedVaultVersionError,
|
|
222
|
+
VerifierResultUnavailable,
|
|
221
223
|
decode_custom_error,
|
|
222
224
|
get_revert_reason,
|
|
223
225
|
register_custom_errors,
|
|
@@ -301,7 +303,7 @@ from ipor_fusion.fuses import (
|
|
|
301
303
|
is_hip3_asset,
|
|
302
304
|
is_native_perp_asset,
|
|
303
305
|
perp_dex_of,
|
|
304
|
-
|
|
306
|
+
precompile_index_of,
|
|
305
307
|
system_address,
|
|
306
308
|
)
|
|
307
309
|
from ipor_fusion.fuses.external_state_events import (
|
|
@@ -309,7 +311,6 @@ from ipor_fusion.fuses.external_state_events import (
|
|
|
309
311
|
EXTERNAL_STATE_EVENTS,
|
|
310
312
|
EXTERNAL_STATE_TOPICS,
|
|
311
313
|
ExternalStateEvent,
|
|
312
|
-
ExternalStateEventDecodeError,
|
|
313
314
|
ExternalStateEventSpec,
|
|
314
315
|
decode_external_state_event,
|
|
315
316
|
external_state_event_name,
|
|
@@ -412,6 +413,7 @@ from ipor_fusion.types import (
|
|
|
412
413
|
Amount,
|
|
413
414
|
AssetId,
|
|
414
415
|
AssetSource,
|
|
416
|
+
CcipChainSelector,
|
|
415
417
|
ChainId,
|
|
416
418
|
Check,
|
|
417
419
|
CommandId,
|
|
@@ -553,7 +555,6 @@ __all__ = [
|
|
|
553
555
|
"BalanceFuseSnapshot",
|
|
554
556
|
"ExternalStateVaultState",
|
|
555
557
|
"read_external_state",
|
|
556
|
-
"NavMark",
|
|
557
558
|
"CrosschainExecutor",
|
|
558
559
|
"StargateCrosschainExecutor",
|
|
559
560
|
"StargateCrosschainDispatcher",
|
|
@@ -582,6 +583,7 @@ __all__ = [
|
|
|
582
583
|
"StargateLane",
|
|
583
584
|
"CcipLane",
|
|
584
585
|
"LaneFuses",
|
|
586
|
+
"LaneHubState",
|
|
585
587
|
"LaneObservation",
|
|
586
588
|
"open_lane",
|
|
587
589
|
"open_lanes",
|
|
@@ -719,7 +721,7 @@ __all__ = [
|
|
|
719
721
|
"is_hip3_asset",
|
|
720
722
|
"is_native_perp_asset",
|
|
721
723
|
"perp_dex_of",
|
|
722
|
-
"
|
|
724
|
+
"precompile_index_of",
|
|
723
725
|
"UniversalTokenSwapperAbi",
|
|
724
726
|
"UniversalTokenSwapperFuse",
|
|
725
727
|
"UniversalTokenSwapperSubstrates",
|
|
@@ -756,6 +758,7 @@ __all__ = [
|
|
|
756
758
|
"LogSourceUnavailable",
|
|
757
759
|
"MorphoMarketNotFoundError",
|
|
758
760
|
"NotPlasmaVaultError",
|
|
761
|
+
"OwnerNotFoundError",
|
|
759
762
|
"TransactionError",
|
|
760
763
|
"SimulationError",
|
|
761
764
|
"SimulationRunError",
|
|
@@ -819,6 +822,7 @@ __all__ = [
|
|
|
819
822
|
"ReturnRequestId",
|
|
820
823
|
"StargateAssetId",
|
|
821
824
|
"LayerZeroEid",
|
|
825
|
+
"CcipChainSelector",
|
|
822
826
|
"TransferId",
|
|
823
827
|
"Price",
|
|
824
828
|
"Period",
|
|
@@ -123,7 +123,7 @@ def morpho_blue(
|
|
|
123
123
|
provider_url = _resolve_provider(cfg, chain_id)
|
|
124
124
|
ctx = Web3Context.from_url(provider_url)
|
|
125
125
|
if block is not None:
|
|
126
|
-
ctx
|
|
126
|
+
ctx = ctx.at_block(block)
|
|
127
127
|
reader = MorphoReader(morpho_blue_address(chain_id))
|
|
128
128
|
mid = market_id
|
|
129
129
|
params, state = reader.read_existing_market(ctx, mid)
|
|
@@ -143,14 +143,14 @@ def morpho_blue(
|
|
|
143
143
|
click.echo(
|
|
144
144
|
json_lib.dumps(
|
|
145
145
|
build_morpho_blue_market_json(
|
|
146
|
-
market_id,
|
|
147
|
-
chain_id,
|
|
148
|
-
params,
|
|
149
|
-
state,
|
|
150
|
-
rates,
|
|
151
|
-
api_market,
|
|
152
|
-
api_error,
|
|
153
|
-
public_allocator,
|
|
146
|
+
market_id=market_id,
|
|
147
|
+
chain_id=chain_id,
|
|
148
|
+
params=params,
|
|
149
|
+
state=state,
|
|
150
|
+
rates=rates,
|
|
151
|
+
api_market=api_market,
|
|
152
|
+
api_error=api_error,
|
|
153
|
+
public_allocator=public_allocator,
|
|
154
154
|
),
|
|
155
155
|
indent=2,
|
|
156
156
|
)
|
|
@@ -123,7 +123,7 @@ def _build_ctx(
|
|
|
123
123
|
provider_url = _resolve_provider(cfg, chain_id)
|
|
124
124
|
ctx = Web3Context.from_url(provider_url)
|
|
125
125
|
if block_number is not None:
|
|
126
|
-
ctx
|
|
126
|
+
ctx = ctx.at_block(block_number)
|
|
127
127
|
return chain_id, ctx
|
|
128
128
|
|
|
129
129
|
|
|
@@ -441,7 +441,7 @@ def oracle_mapping(
|
|
|
441
441
|
effective_block = (
|
|
442
442
|
block_number if block_number is not None else ctx.web3.eth.block_number
|
|
443
443
|
)
|
|
444
|
-
ctx
|
|
444
|
+
ctx = ctx.at_block(effective_block)
|
|
445
445
|
|
|
446
446
|
try:
|
|
447
447
|
resolve_access_manager(ctx, vault_address)
|