ipor-fusion 4.0.0.dev129__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.dev129 → ipor_fusion-4.0.0.dev137}/AGENTS.md +9 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/MIGRATION_4.md +57 -13
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/examples/advanced_euler_v2_credit_market_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/examples/advanced_euler_v2_looping_arbitrum.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +8 -9
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +4 -5
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/examples/external_state_margin_leg_base.py +4 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/examples/simple_aave_v3_supply_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/scripts/crosschain_readiness.py +5 -7
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/__init__.py +10 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/market_cmd.py +9 -9
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/options.py +1 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_cmd.py +1 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/access.py +9 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/context.py +2 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/contract.py +1 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/external_state_executor.py +18 -13
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/multicall.py +1 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/oracle.py +5 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/plasma_vault.py +6 -5
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/__init__.py +8 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/__init__.py +1 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/chainlink.py +9 -8
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/codec.py +8 -8
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/contracts.py +5 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/indexer.py +1 -8
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/transport.py +3 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/fuses/ccip.py +2 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/lane.py +67 -5
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/dependency_graph.py +2 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/errors.py +19 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/explorer.py +2 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/__init__.py +2 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/external_state_events.py +1 -7
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/hypercore.py +2 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/market_info.py +6 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/mcp/server.py +10 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/hypercore.py +11 -9
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/hypercore_outcome.py +2 -5
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/unpriceable.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/substrates.py +2 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/types.py +2 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_data.py +6 -6
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_crosschain.py +1 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_crosschain_lifecycle.py +6 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_access_manager.py +14 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_commands.py +1 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_oracle_mapping.py +7 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_lane.py +110 -1
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_error_hierarchy.py +12 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_explorer.py +11 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_external_state_executor.py +4 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_fuse_encoding.py +3 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_deployment.py +1 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_live.py +8 -6
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_outcome.py +1 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_readers.py +6 -6
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_simulation.py +0 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_mcp_server.py +7 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_public_api.py +10 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_borrow_aave_v3_mainnet.py +6 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_claim_merkl_wrapper_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_claim_morpho_rewards.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_crosschain_hypercore.py +1 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_crosschain_hyperevm.py +1 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_batch_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_credit_market_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_swap_deploy_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_euler_v2_swap_registry_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_external_state_executor_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_looping_aave_v3_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_looping_morpho_blue_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_morpho_blue.py +0 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_pilot_v3.py +12 -8
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_pilot_v4_uniswap.py +15 -10
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_pilot_v5_ramses.py +12 -8
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_pilot_v5_scheduled.py +18 -12
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_readers_integration.py +1 -3
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_release_funds.py +6 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_swap_on_base.py +6 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_vault_from_scratch_base.py +3 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_unpriceable_tokens.py +5 -5
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +1 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_web3_context.py +2 -4
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/typed_client/consumer.py +62 -2
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/typed_client/rejected.py +28 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/README.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev129 → ipor_fusion-4.0.0.dev137}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev129 → 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,21 @@ 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
282
|
takes a `ProposalHash`; `BalanceProposal.proposal_hash` is a `ProposalHash`;
|
|
259
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.
|
|
260
288
|
`ExternalStateExecutor.mark_nav` and `NavMark` are gone: send `propose_balance` and
|
|
261
289
|
`confirm_balance` from separate custodians, then
|
|
262
290
|
`PlasmaVault.update_markets_balances([IporFusionMarkets.EXTERNAL_STATE])`.
|
|
@@ -327,7 +355,8 @@ placeholder wrapper.
|
|
|
327
355
|
`.decode(raw)` and `.map(f)` need no context. `Call(...)` no longer takes `ctx=`.
|
|
328
356
|
- A wrapper method that executes to answer (storage, log scans, dependent reads) is
|
|
329
357
|
named `read_*` and takes the context first (table below).
|
|
330
|
-
- 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,
|
|
331
360
|
every re-run of a failed sub-call and the per-call fallback run on its `ctx`, so a
|
|
332
361
|
pinned context keeps them all at its block; it is no longer a `ContractWrapper`,
|
|
333
362
|
`aggregate3(calls)` still returns the raw `Call`), `VaultSimulator`,
|
|
@@ -342,7 +371,14 @@ placeholder wrapper.
|
|
|
342
371
|
`command_in_flight` and `transfer_in_flight` read on `hub_ctx`. The Calls a lane
|
|
343
372
|
returns are unexecuted, and the executor and dispatcher share one address, so pick
|
|
344
373
|
the context yourself: `lane.get_balance().call(lane.hub_ctx)`,
|
|
345
|
-
`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)`
|
|
346
382
|
and `.dispatcher(address)` no longer take a context.
|
|
347
383
|
- Chain-bound decoding takes the chain explicitly:
|
|
348
384
|
`ExternalStateExecutor.pending_proposals(account, *, chain_id)`,
|
|
@@ -380,6 +416,10 @@ placeholder wrapper.
|
|
|
380
416
|
| `MorphoReader.rates_from(market, params)` | `MorphoReader.read_rates_from(ctx, market, params)` (it reads the IRM) |
|
|
381
417
|
| `AaveV3Reader.position_breakdown(asset, user)` | `AaveV3Reader.read_position_breakdown(ctx, asset, user)` |
|
|
382
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)` |
|
|
383
423
|
| `executor.pending_proposals(account)` | `executor.pending_proposals(account, chain_id=ctx.chain_id)` |
|
|
384
424
|
| `executor.parse_balance_proposed(log)` / `find_balance_proposed(logs)` | `...(log, chain_id=...)` / `...(logs, chain_id=...)` |
|
|
385
425
|
| `CcipLane(executor=, dispatcher=, spoke_chain_id=, ...)` | `CcipLane(hub_ctx=, spoke_ctx=, executor=, dispatcher=, ...)` (same for `StargateLane`) |
|
|
@@ -512,8 +552,12 @@ is the wrong one.
|
|
|
512
552
|
- `MorphoApiError` (still a `RuntimeError`), `ExternalStateEventDecodeError` (still a
|
|
513
553
|
`ValueError`) and `VerifierResultUnavailable` (still a `LookupError`) now derive
|
|
514
554
|
from `IporFusionError`, so an `except IporFusionError` placed before their own
|
|
515
|
-
handlers catches them first.
|
|
516
|
-
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`.
|
|
517
561
|
- `EmptyCallResultError` is no longer an eth_abi `InsufficientDataBytes` (nor a
|
|
518
562
|
`DecodingError`). Code that caught either around `.call()` to tolerate a missing
|
|
519
563
|
contract or getter must catch `EmptyCallResultError`; return data that is present
|
|
@@ -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.dev129 → 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.dev129 → 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
|
|
|
@@ -931,7 +932,7 @@ def run_simulation(web3: Web3) -> SimulationResult:
|
|
|
931
932
|
# to one custodian by either route, however separate the two keys are -- and
|
|
932
933
|
# that is why a production deployment cannot drive both halves from one
|
|
933
934
|
# process, whatever this example does under simulation.
|
|
934
|
-
proposed_at = baseline_timestamp + PROPOSE_OFFSET
|
|
935
|
+
proposed_at = Timestamp(baseline_timestamp + PROPOSE_OFFSET)
|
|
935
936
|
proposal_hash = ExternalStateExecutor.proposal_hash(
|
|
936
937
|
executor=executor_address,
|
|
937
938
|
chain_id=BASE_CHAIN_ID,
|
{ipor_fusion-4.0.0.dev129 → 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]:
|
|
@@ -144,6 +144,7 @@ from ipor_fusion.crosschain import (
|
|
|
144
144
|
EVMTokenAmount,
|
|
145
145
|
ExecutorInitParams,
|
|
146
146
|
LaneFuses,
|
|
147
|
+
LaneHubState,
|
|
147
148
|
LaneObservation,
|
|
148
149
|
MessageExecutionState,
|
|
149
150
|
MessageV1,
|
|
@@ -168,7 +169,6 @@ from ipor_fusion.crosschain import (
|
|
|
168
169
|
TaxiMessage,
|
|
169
170
|
TokenTransferV1,
|
|
170
171
|
VerifierResult,
|
|
171
|
-
VerifierResultUnavailable,
|
|
172
172
|
ccip_events,
|
|
173
173
|
ccip_receive_calldata,
|
|
174
174
|
ccip_token_lane,
|
|
@@ -205,18 +205,21 @@ from ipor_fusion.errors import (
|
|
|
205
205
|
CrosschainDiscoveryError,
|
|
206
206
|
EmptyCallResultError,
|
|
207
207
|
ExternalStateError,
|
|
208
|
+
ExternalStateEventDecodeError,
|
|
208
209
|
HyperCoreValuationError,
|
|
209
210
|
IporFusionError,
|
|
210
211
|
LogScanError,
|
|
211
212
|
LogSourceUnavailable,
|
|
212
213
|
MorphoMarketNotFoundError,
|
|
213
214
|
NotPlasmaVaultError,
|
|
215
|
+
OwnerNotFoundError,
|
|
214
216
|
SimulationError,
|
|
215
217
|
SimulationRunError,
|
|
216
218
|
TransactionError,
|
|
217
219
|
UnsupportedChainError,
|
|
218
220
|
UnsupportedContractVersionError,
|
|
219
221
|
UnsupportedVaultVersionError,
|
|
222
|
+
VerifierResultUnavailable,
|
|
220
223
|
decode_custom_error,
|
|
221
224
|
get_revert_reason,
|
|
222
225
|
register_custom_errors,
|
|
@@ -300,7 +303,7 @@ from ipor_fusion.fuses import (
|
|
|
300
303
|
is_hip3_asset,
|
|
301
304
|
is_native_perp_asset,
|
|
302
305
|
perp_dex_of,
|
|
303
|
-
|
|
306
|
+
precompile_index_of,
|
|
304
307
|
system_address,
|
|
305
308
|
)
|
|
306
309
|
from ipor_fusion.fuses.external_state_events import (
|
|
@@ -308,7 +311,6 @@ from ipor_fusion.fuses.external_state_events import (
|
|
|
308
311
|
EXTERNAL_STATE_EVENTS,
|
|
309
312
|
EXTERNAL_STATE_TOPICS,
|
|
310
313
|
ExternalStateEvent,
|
|
311
|
-
ExternalStateEventDecodeError,
|
|
312
314
|
ExternalStateEventSpec,
|
|
313
315
|
decode_external_state_event,
|
|
314
316
|
external_state_event_name,
|
|
@@ -411,6 +413,7 @@ from ipor_fusion.types import (
|
|
|
411
413
|
Amount,
|
|
412
414
|
AssetId,
|
|
413
415
|
AssetSource,
|
|
416
|
+
CcipChainSelector,
|
|
414
417
|
ChainId,
|
|
415
418
|
Check,
|
|
416
419
|
CommandId,
|
|
@@ -580,6 +583,7 @@ __all__ = [
|
|
|
580
583
|
"StargateLane",
|
|
581
584
|
"CcipLane",
|
|
582
585
|
"LaneFuses",
|
|
586
|
+
"LaneHubState",
|
|
583
587
|
"LaneObservation",
|
|
584
588
|
"open_lane",
|
|
585
589
|
"open_lanes",
|
|
@@ -717,7 +721,7 @@ __all__ = [
|
|
|
717
721
|
"is_hip3_asset",
|
|
718
722
|
"is_native_perp_asset",
|
|
719
723
|
"perp_dex_of",
|
|
720
|
-
"
|
|
724
|
+
"precompile_index_of",
|
|
721
725
|
"UniversalTokenSwapperAbi",
|
|
722
726
|
"UniversalTokenSwapperFuse",
|
|
723
727
|
"UniversalTokenSwapperSubstrates",
|
|
@@ -754,6 +758,7 @@ __all__ = [
|
|
|
754
758
|
"LogSourceUnavailable",
|
|
755
759
|
"MorphoMarketNotFoundError",
|
|
756
760
|
"NotPlasmaVaultError",
|
|
761
|
+
"OwnerNotFoundError",
|
|
757
762
|
"TransactionError",
|
|
758
763
|
"SimulationError",
|
|
759
764
|
"SimulationRunError",
|
|
@@ -817,6 +822,7 @@ __all__ = [
|
|
|
817
822
|
"ReturnRequestId",
|
|
818
823
|
"StargateAssetId",
|
|
819
824
|
"LayerZeroEid",
|
|
825
|
+
"CcipChainSelector",
|
|
820
826
|
"TransferId",
|
|
821
827
|
"Price",
|
|
822
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)
|
|
@@ -18,6 +18,7 @@ from ipor_fusion.errors import (
|
|
|
18
18
|
ContractNotFoundError,
|
|
19
19
|
EmptyCallResultError,
|
|
20
20
|
NotPlasmaVaultError,
|
|
21
|
+
OwnerNotFoundError,
|
|
21
22
|
)
|
|
22
23
|
from ipor_fusion.types import AccessManagerAddress, Period, PlasmaVaultAddress, RoleId
|
|
23
24
|
|
|
@@ -112,7 +113,14 @@ class AccessManager(ContractWrapper):
|
|
|
112
113
|
# ── Composite reads on ``ctx``: event replay + batched hasRole reads ───
|
|
113
114
|
|
|
114
115
|
def read_owner(self, ctx: Web3Context) -> ChecksumAddress:
|
|
115
|
-
|
|
116
|
+
"""The first of :meth:`read_owners`; raises `OwnerNotFoundError` when no
|
|
117
|
+
account holds ``OWNER_ROLE``."""
|
|
118
|
+
owners = self.read_owners(ctx)
|
|
119
|
+
if not owners:
|
|
120
|
+
raise OwnerNotFoundError(
|
|
121
|
+
f"access manager {self._address} has no account with OWNER_ROLE"
|
|
122
|
+
)
|
|
123
|
+
return owners[0]
|
|
116
124
|
|
|
117
125
|
def read_owners(self, ctx: Web3Context) -> list[ChecksumAddress]:
|
|
118
126
|
return [
|
|
@@ -140,12 +140,10 @@ class Web3Context:
|
|
|
140
140
|
|
|
141
141
|
@property
|
|
142
142
|
def default_block(self) -> BlockIdentifier:
|
|
143
|
+
"""The block reads default to: ``"latest"`` unless this context came
|
|
144
|
+
from `at_block`. Read-only; pin a copy with `at_block` instead."""
|
|
143
145
|
return self._default_block
|
|
144
146
|
|
|
145
|
-
@default_block.setter
|
|
146
|
-
def default_block(self, value: BlockIdentifier) -> None:
|
|
147
|
-
self._default_block = value
|
|
148
|
-
|
|
149
147
|
def at_block(self, block: BlockIdentifier) -> Web3Context:
|
|
150
148
|
"""A copy of this context whose reads default to ``block``: same
|
|
151
149
|
connection, signer, log source, cache and scan bounds. Pinning a copy leaves
|
|
@@ -134,7 +134,7 @@ class ContractWrapper:
|
|
|
134
134
|
|
|
135
135
|
A method that must execute to answer (a storage read, a log scan, a read
|
|
136
136
|
that depends on another read) is named ``read_*`` and takes the context as
|
|
137
|
-
its first argument.
|
|
137
|
+
its first argument; no other method carries the prefix.
|
|
138
138
|
"""
|
|
139
139
|
|
|
140
140
|
def __init__(self, address: ChecksumAddress):
|