ipor-fusion 4.0.0.dev49__tar.gz → 4.0.0.dev54__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.dev49 → ipor_fusion-4.0.0.dev54}/MIGRATION_4.md +25 -9
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/__init__.py +4 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/vault_markets_view.py +6 -4
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/context.py +6 -6
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/dependency_graph.py +3 -1
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/errors.py +2 -2
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/explorer.py +14 -4
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/events.py +8 -1
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/external_state_events.py +3 -3
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/ramses_v2.py +3 -3
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/uniswap_v3.py +4 -4
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/hypercore.py +1 -1
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/lending_health.py +1 -1
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/substrates.py +19 -23
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/types.py +25 -1
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/validation.py +2 -2
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/vault_data.py +16 -15
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/vault_info.py +9 -4
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_helpers.py +4 -4
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_encoding.py +2 -2
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_explorer.py +11 -2
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_fuse_encoding.py +4 -4
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_revert_decoding.py +11 -8
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_substrates.py +12 -12
- ipor_fusion-4.0.0.dev54/tests/test_types_and_events.py +122 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_web3_context.py +1 -1
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/typed_client/consumer.py +5 -0
- ipor_fusion-4.0.0.dev49/tests/test_types_and_events.py +0 -63
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/AGENTS.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/README.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/crosschain/base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/crosschain/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/crosschain/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/mcp/server.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/uv.lock +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
vault/oracle/token addresses and transaction hashes a nominal type
|
|
5
5
|
(`typing.NewType`) across the public API, and checks the SDK, the examples and a
|
|
6
6
|
typed client with pyright's `reportArgumentType`. Other fields keep their types
|
|
7
|
-
(e.g.
|
|
7
|
+
(e.g. symbols, names and URLs stay `str`).
|
|
8
8
|
|
|
9
9
|
The wrappers do not change values: `ChainId(1)` is `1` at runtime. The
|
|
10
10
|
[behavior changes](#behavior-changes) below, however, apply to **every** caller,
|
|
@@ -15,7 +15,7 @@ type-checked or not. In particular, `fetch_market` and
|
|
|
15
15
|
returns already carry their type and go back in unwrapped.
|
|
16
16
|
|
|
17
17
|
All types are importable from `ipor_fusion` (and `ipor_fusion.types`);
|
|
18
|
-
`ChecksumAddress
|
|
18
|
+
`ChecksumAddress` and `HexAddress` come from `eth_typing`,
|
|
19
19
|
`BlockIdentifier` from `web3.types`, and `USDC_TOKEN_INDEX` / `hip3_action_asset` from
|
|
20
20
|
`ipor_fusion.fuses.hypercore`. The wrappers label values; they do not validate byte
|
|
21
21
|
widths or address spelling.
|
|
@@ -29,9 +29,9 @@ widths or address spelling.
|
|
|
29
29
|
| `RoleId` | a `Roles` member (accepted as is), or `RoleId(n)`; `Roles.resolve(name)` returns one |
|
|
30
30
|
| `Decimals`, `Period`, `Amount`, ... | `Decimals(8)`, `Period(0)`, `Amount(n)` (unchanged) |
|
|
31
31
|
| `ChecksumAddress` | `Web3.to_checksum_address(value)` |
|
|
32
|
-
| `HexAddress` | any `ChecksumAddress`, or `
|
|
32
|
+
| `HexAddress` | any `ChecksumAddress`, or `parse_hex_address(value)` (20 bytes or hex in any spelling → lowercase `0x` form) |
|
|
33
33
|
| `MorphoBlueMarketId` | `parse_morpho_market_id(value)`: 32 bytes or hex in any spelling, always `0x` + 64 lowercase digits |
|
|
34
|
-
| `TxHash` | `
|
|
34
|
+
| `TxHash` | `parse_tx_hash(value)` (32 bytes or hex in any spelling) |
|
|
35
35
|
| 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
36
|
| 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)` |
|
|
37
37
|
| external state | `ProposalHash(b)` |
|
|
@@ -59,11 +59,18 @@ and the `dependency_graph` helpers (`compute_update_reach`, `compute_update_grou
|
|
|
59
59
|
`find_orphan_fuse_markets`, `find_markets_missing_erc20_dependency`).
|
|
60
60
|
A custom `VaultState` implementation also annotates `asset` as `ChecksumAddress` and
|
|
61
61
|
its `unpriceable_priced_tokens` items' `market_id` as `MarketId`
|
|
62
|
-
(`UnpriceableToken`)
|
|
63
|
-
`ChecksumAddress`,
|
|
62
|
+
(`UnpriceableToken`), and `price_oracle_addr` / `fuse_markets` keys as
|
|
63
|
+
`ChecksumAddress`. `VaultData.asset`, `access_manager`, `price_oracle_addr`,
|
|
64
|
+
`rewards_manager`, `withdraw_manager`, `fuses` and `instant_fuses` (and the
|
|
65
|
+
`fuse_markets` keys), `FeeData.fee_manager` / `ipor_dao_fee_recipient`, and
|
|
66
|
+
`VaultValidation.vault` / `asset` are `ChecksumAddress`; `VaultData.balance_fuses`
|
|
67
|
+
is `list[BalanceFuse]` and `token_prices_usd` is keyed by `HexAddress` (lowercase);
|
|
68
|
+
the Uniswap V3 / Ramses V2 position events' `version`, `sender` and `recipient` are
|
|
69
|
+
`ChecksumAddress`;
|
|
64
70
|
`VaultValidation.chain_id` is `ChainId`; `LendingMarketHealth.market_id` and
|
|
65
|
-
`MiddlewarePricedToken.market_id` are `MarketId`; `Erc20Holding.address`
|
|
66
|
-
`SubstrateInfo.address`
|
|
71
|
+
`MiddlewarePricedToken.market_id` are `MarketId`; `Erc20Holding.address` is
|
|
72
|
+
`HexAddress`, and `SubstrateInfo.address` is `HexAddress | None` (`None`, no longer
|
|
73
|
+
`""`, when a substrate carries no address).
|
|
67
74
|
`LegacyPriceOracleMiddleware` takes `base_currency_decimals: Decimals`.
|
|
68
75
|
`get_logs_adaptive(chain_id=)` and `LogSource.get_logs` take `ChainId`;
|
|
69
76
|
`quote_ccip_native_fee(block=)` and `OracleMappingReader.asset_source_events` take a
|
|
@@ -112,7 +119,9 @@ takes a `ProposalHash`; `BalanceProposal.proposal_hash` and `NavMark.proposal_ha
|
|
|
112
119
|
are `ProposalHash`; `ExternalStateEvent.transaction_hash` is a `TxHash`.
|
|
113
120
|
|
|
114
121
|
**Errors and explorer.** `TransactionError(tx_hash=)` takes a `TxHash`,
|
|
115
|
-
`LogScanError(address=)` a `ChecksumAddress`; `
|
|
122
|
+
`LogScanError(address=)` a `ChecksumAddress`; `get_revert_reason` takes a `TxHash`;
|
|
123
|
+
`get_deployment_tx` returns a `TxHash`
|
|
124
|
+
(a malformed hash from Etherscan is reported as the error `malformed-tx-hash`).
|
|
116
125
|
|
|
117
126
|
**MCP response models** (Python constructors only; the JSON schemas are unchanged
|
|
118
127
|
except below): `chain_id` fields are `ChainId`, `role_id` `RoleId`, `market_id`
|
|
@@ -128,6 +137,13 @@ except below): `chain_id` fields are `ChainId`, `role_id` `RoleId`, `market_id`
|
|
|
128
137
|
|
|
129
138
|
- The MCP `vault_info` document reports the vault address checksummed (the CLI
|
|
130
139
|
already did).
|
|
140
|
+
- `SubstrateInfo.address` is `None` instead of `""` for a substrate without an
|
|
141
|
+
address. Truthiness checks are unaffected and the SDK's JSON documents already
|
|
142
|
+
omit it, but `dataclasses.asdict(info)` now gives `"address": None` and
|
|
143
|
+
`info.address == ""` is false.
|
|
144
|
+
- The Uniswap V3 / Ramses V2 position events (`extract_new_position_events`,
|
|
145
|
+
`extract_close_position_events`) return their addresses checksummed (they were the
|
|
146
|
+
lowercase ABI-decoded strings).
|
|
131
147
|
- `fusion market meta-morpho --json` and the MCP `market_meta_morpho` tool report
|
|
132
148
|
`null` instead of `""` for an absent curator, guardian or fee recipient; the MCP
|
|
133
149
|
schema's `curator` is nullable.
|
|
@@ -345,7 +345,9 @@ from ipor_fusion.types import (
|
|
|
345
345
|
TokenId,
|
|
346
346
|
TransferId,
|
|
347
347
|
TxHash,
|
|
348
|
+
parse_hex_address,
|
|
348
349
|
parse_morpho_market_id,
|
|
350
|
+
parse_tx_hash,
|
|
349
351
|
)
|
|
350
352
|
from ipor_fusion.validation import (
|
|
351
353
|
Erc20Holding,
|
|
@@ -624,7 +626,9 @@ __all__ = [
|
|
|
624
626
|
"PayloadHash",
|
|
625
627
|
"ProposalHash",
|
|
626
628
|
"TxHash",
|
|
629
|
+
"parse_hex_address",
|
|
627
630
|
"parse_morpho_market_id",
|
|
631
|
+
"parse_tx_hash",
|
|
628
632
|
"AssetId",
|
|
629
633
|
"CommandId",
|
|
630
634
|
"DeploymentRequestId",
|
{ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/cli/vault_markets_view.py
RENAMED
|
@@ -20,7 +20,7 @@ from ipor_fusion.substrates import (
|
|
|
20
20
|
decode_substrate,
|
|
21
21
|
format_market_label,
|
|
22
22
|
)
|
|
23
|
-
from ipor_fusion.types import ChainId, MarketId
|
|
23
|
+
from ipor_fusion.types import ChainId, MarketId, parse_hex_address
|
|
24
24
|
from ipor_fusion.vault_data import (
|
|
25
25
|
GET_MARKET_SUBSTRATES,
|
|
26
26
|
VaultData,
|
|
@@ -213,7 +213,7 @@ def _format_token_amount(
|
|
|
213
213
|
ctx: Web3Context,
|
|
214
214
|
raw: int,
|
|
215
215
|
token_address: HexAddress,
|
|
216
|
-
prices_usd: dict[
|
|
216
|
+
prices_usd: dict[HexAddress, float] | None = None,
|
|
217
217
|
) -> str:
|
|
218
218
|
"""Format a raw on-chain amount using cached ERC-20 symbol + decimals.
|
|
219
219
|
|
|
@@ -226,7 +226,9 @@ def _format_token_amount(
|
|
|
226
226
|
return f"{raw} raw ({symbol})"
|
|
227
227
|
base = f"{_format_amount(raw, decimals)} {symbol}"
|
|
228
228
|
if prices_usd:
|
|
229
|
-
usd_suffix = _format_usd(
|
|
229
|
+
usd_suffix = _format_usd(
|
|
230
|
+
raw, decimals, prices_usd.get(parse_hex_address(token_address))
|
|
231
|
+
)
|
|
230
232
|
return f"{base}{usd_suffix}"
|
|
231
233
|
return base
|
|
232
234
|
|
|
@@ -259,7 +261,7 @@ def _print_dependency_graph(data: VaultData) -> None:
|
|
|
259
261
|
def _print_fuse_section(
|
|
260
262
|
title: str,
|
|
261
263
|
fuses: Sequence[ChecksumAddress],
|
|
262
|
-
fuse_markets: dict[
|
|
264
|
+
fuse_markets: dict[ChecksumAddress, MarketId] | None,
|
|
263
265
|
market_substrates: dict[MarketId, list[bytes]] | None,
|
|
264
266
|
chain_id: ChainId,
|
|
265
267
|
api_key: str | None,
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
from eth_account import Account
|
|
6
|
-
from eth_typing import ChecksumAddress
|
|
6
|
+
from eth_typing import ChecksumAddress
|
|
7
7
|
from hexbytes import HexBytes
|
|
8
8
|
from requests import ConnectionError as RequestsConnectionError
|
|
9
9
|
from requests import HTTPError, Timeout
|
|
@@ -25,7 +25,7 @@ from ipor_fusion.core.logs import (
|
|
|
25
25
|
get_logs_adaptive,
|
|
26
26
|
)
|
|
27
27
|
from ipor_fusion.errors import LogSourceUnavailable, TransactionError, get_revert_reason
|
|
28
|
-
from ipor_fusion.types import ChainId,
|
|
28
|
+
from ipor_fusion.types import ChainId, parse_tx_hash
|
|
29
29
|
|
|
30
30
|
# web3 retries every allowlisted method on any HTTP error, a 400 included;
|
|
31
31
|
# a too-wide eth_getLogs answered with HTTP 400/413 or a query timeout would be
|
|
@@ -224,13 +224,13 @@ class Web3Context:
|
|
|
224
224
|
"data": data_hex,
|
|
225
225
|
}
|
|
226
226
|
|
|
227
|
-
def _handle_receipt(self, tx_hash, receipt) -> TxReceipt:
|
|
227
|
+
def _handle_receipt(self, tx_hash: bytes, receipt: TxReceipt) -> TxReceipt:
|
|
228
228
|
if receipt["status"] != 1:
|
|
229
|
-
|
|
229
|
+
parsed = parse_tx_hash(tx_hash)
|
|
230
230
|
raise TransactionError(
|
|
231
231
|
"Transaction failed",
|
|
232
|
-
tx_hash=
|
|
233
|
-
revert_reason=
|
|
232
|
+
tx_hash=parsed,
|
|
233
|
+
revert_reason=get_revert_reason(self.web3, parsed, receipt),
|
|
234
234
|
)
|
|
235
235
|
return receipt
|
|
236
236
|
|
|
@@ -4,6 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from collections.abc import Mapping, Sequence, Set
|
|
6
6
|
|
|
7
|
+
from eth_typing import ChecksumAddress
|
|
8
|
+
|
|
7
9
|
from ipor_fusion.market_ids import IporFusionMarkets
|
|
8
10
|
from ipor_fusion.types import MarketId
|
|
9
11
|
|
|
@@ -38,7 +40,7 @@ _ERC20_DEP_NOT_REQUIRED: frozenset[MarketId] = frozenset(
|
|
|
38
40
|
|
|
39
41
|
|
|
40
42
|
def find_orphan_fuse_markets(
|
|
41
|
-
fuse_markets: Mapping[
|
|
43
|
+
fuse_markets: Mapping[ChecksumAddress, MarketId],
|
|
42
44
|
balance_fuse_market_ids: Set[MarketId],
|
|
43
45
|
) -> dict[MarketId, list[str]]:
|
|
44
46
|
"""Return markets claimed by action fuses but lacking a balance fuse.
|
|
@@ -115,10 +115,10 @@ def _decode_revert_reason(data: bytes) -> str:
|
|
|
115
115
|
return hex_str
|
|
116
116
|
|
|
117
117
|
|
|
118
|
-
def get_revert_reason(web3: Web3, tx_hash:
|
|
118
|
+
def get_revert_reason(web3: Web3, tx_hash: TxHash, receipt: TxReceipt) -> str | None:
|
|
119
119
|
"""Replay a failed tx as eth_call to capture revert data."""
|
|
120
120
|
try:
|
|
121
|
-
tx = web3.eth.get_transaction(tx_hash)
|
|
121
|
+
tx = web3.eth.get_transaction(tx_hash)
|
|
122
122
|
call_params = {
|
|
123
123
|
"from": tx["from"],
|
|
124
124
|
"to": tx["to"],
|
|
@@ -10,10 +10,10 @@ import time
|
|
|
10
10
|
from urllib.parse import urlencode
|
|
11
11
|
from urllib.request import urlopen
|
|
12
12
|
|
|
13
|
-
from eth_typing import HexAddress
|
|
13
|
+
from eth_typing import HexAddress
|
|
14
14
|
|
|
15
15
|
from ipor_fusion.cache import cache_key, load_contract_cache, update_contract_cache
|
|
16
|
-
from ipor_fusion.types import ChainId, TxHash
|
|
16
|
+
from ipor_fusion.types import ChainId, TxHash, parse_tx_hash
|
|
17
17
|
|
|
18
18
|
ETHERSCAN_V2_URL = "https://api.etherscan.io/v2/api"
|
|
19
19
|
|
|
@@ -67,6 +67,17 @@ def get_deployment_tx(
|
|
|
67
67
|
return _fetch_contract_creation_tx(chain_id, address, api_key)
|
|
68
68
|
|
|
69
69
|
|
|
70
|
+
def _creation_tx_hash(raw: object) -> tuple[TxHash | None, str | None]:
|
|
71
|
+
if not raw:
|
|
72
|
+
return None, None
|
|
73
|
+
if not isinstance(raw, str):
|
|
74
|
+
return None, "malformed-tx-hash"
|
|
75
|
+
try:
|
|
76
|
+
return parse_tx_hash(raw), None
|
|
77
|
+
except ValueError:
|
|
78
|
+
return None, "malformed-tx-hash"
|
|
79
|
+
|
|
80
|
+
|
|
70
81
|
def _fetch_contract_creation_tx(
|
|
71
82
|
chain_id: ChainId, address: HexAddress, api_key: str | None = None
|
|
72
83
|
) -> tuple[TxHash | None, str | None]:
|
|
@@ -91,8 +102,7 @@ def _fetch_contract_creation_tx(
|
|
|
91
102
|
with urlopen(url, timeout=10) as resp: # noqa: S310
|
|
92
103
|
data = json.loads(resp.read().decode())
|
|
93
104
|
if data.get("status") == "1" and data.get("result"):
|
|
94
|
-
|
|
95
|
-
return (TxHash(HexStr(tx_hash)) if tx_hash else None), None
|
|
105
|
+
return _creation_tx_hash(data["result"][0].get("txHash"))
|
|
96
106
|
result_text = str(data.get("result", "")).lower()
|
|
97
107
|
if "free api access is not supported" in result_text:
|
|
98
108
|
return None, "etherscan-paid-tier-required"
|
|
@@ -14,5 +14,12 @@ def extract_events(
|
|
|
14
14
|
for log in receipt["logs"]:
|
|
15
15
|
if log["topics"][0] == sig_hash:
|
|
16
16
|
decoded = decode(abi_types, log["data"])
|
|
17
|
-
events.append(
|
|
17
|
+
events.append(
|
|
18
|
+
dataclass_type(
|
|
19
|
+
*(
|
|
20
|
+
Web3.to_checksum_address(value) if abi == "address" else value
|
|
21
|
+
for abi, value in zip(abi_types, decoded, strict=True)
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
)
|
|
18
25
|
return events
|
{ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/fuses/external_state_events.py
RENAMED
|
@@ -28,11 +28,11 @@ from typing import Any
|
|
|
28
28
|
|
|
29
29
|
from eth_abi import decode
|
|
30
30
|
from eth_abi.exceptions import DecodingError
|
|
31
|
-
from eth_typing import ChecksumAddress
|
|
31
|
+
from eth_typing import ChecksumAddress
|
|
32
32
|
from web3 import Web3
|
|
33
33
|
from web3.types import TxReceipt
|
|
34
34
|
|
|
35
|
-
from ipor_fusion.types import TxHash
|
|
35
|
+
from ipor_fusion.types import TxHash, parse_tx_hash
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
@dataclass(frozen=True, slots=True)
|
|
@@ -196,7 +196,7 @@ def external_state_event_name(topic: bytes | str) -> str | None:
|
|
|
196
196
|
def _hex(value: Any) -> TxHash | None:
|
|
197
197
|
if value is None:
|
|
198
198
|
return None
|
|
199
|
-
return
|
|
199
|
+
return parse_tx_hash(_as_bytes(value, "transactionHash"))
|
|
200
200
|
|
|
201
201
|
|
|
202
202
|
def decode_external_state_event(log: Mapping[str, Any]) -> ExternalStateEvent | None:
|
|
@@ -136,13 +136,13 @@ class RamsesClaimFuse(Fuse):
|
|
|
136
136
|
|
|
137
137
|
@dataclass(slots=True)
|
|
138
138
|
class RamsesNewPositionEvent:
|
|
139
|
-
version:
|
|
139
|
+
version: ChecksumAddress
|
|
140
140
|
token_id: TokenId
|
|
141
141
|
liquidity: Liquidity
|
|
142
142
|
amount0: Amount
|
|
143
143
|
amount1: Amount
|
|
144
|
-
sender:
|
|
145
|
-
recipient:
|
|
144
|
+
sender: ChecksumAddress
|
|
145
|
+
recipient: ChecksumAddress
|
|
146
146
|
fee: Fee
|
|
147
147
|
tick_lower: Tick
|
|
148
148
|
tick_upper: Tick
|
|
@@ -140,13 +140,13 @@ class UniswapV3CollectFuse(Fuse):
|
|
|
140
140
|
|
|
141
141
|
@dataclass(slots=True)
|
|
142
142
|
class UniswapV3NewPositionEvent:
|
|
143
|
-
version:
|
|
143
|
+
version: ChecksumAddress
|
|
144
144
|
token_id: TokenId
|
|
145
145
|
liquidity: Liquidity
|
|
146
146
|
amount0: Amount
|
|
147
147
|
amount1: Amount
|
|
148
|
-
sender:
|
|
149
|
-
recipient:
|
|
148
|
+
sender: ChecksumAddress
|
|
149
|
+
recipient: ChecksumAddress
|
|
150
150
|
fee: Fee
|
|
151
151
|
tick_lower: Tick
|
|
152
152
|
tick_upper: Tick
|
|
@@ -154,7 +154,7 @@ class UniswapV3NewPositionEvent:
|
|
|
154
154
|
|
|
155
155
|
@dataclass(slots=True)
|
|
156
156
|
class UniswapV3ClosePositionEvent:
|
|
157
|
-
version:
|
|
157
|
+
version: ChecksumAddress
|
|
158
158
|
token_id: TokenId
|
|
159
159
|
|
|
160
160
|
|
|
@@ -499,7 +499,7 @@ def _market_layout(
|
|
|
499
499
|
bitmap = 0
|
|
500
500
|
for raw in substrates:
|
|
501
501
|
info = decode_substrate(raw, HYPERCORE_MARKET)
|
|
502
|
-
if info.type_label == "SPOT_TOKEN" and not info.is_error:
|
|
502
|
+
if info.type_label == "SPOT_TOKEN" and not info.is_error and info.address:
|
|
503
503
|
index = HyperCoreTokenIndex(int(info.extra["token_index"]))
|
|
504
504
|
if index in seen:
|
|
505
505
|
continue
|
{ipor_fusion-4.0.0.dev49 → ipor_fusion-4.0.0.dev54}/src/ipor_fusion/readers/lending_health.py
RENAMED
|
@@ -353,7 +353,7 @@ def _aave_v4_spokes(substrates: list[bytes]) -> list[ChecksumAddress]:
|
|
|
353
353
|
spokes: dict[ChecksumAddress, None] = {}
|
|
354
354
|
for sub in substrates:
|
|
355
355
|
info = decode_substrate(sub, market_id=IporFusionMarkets.AAVE_V4)
|
|
356
|
-
if info.type_label == "AAVE_V4_RESERVE":
|
|
356
|
+
if info.type_label == "AAVE_V4_RESERVE" and info.address:
|
|
357
357
|
spokes[Web3.to_checksum_address(info.address)] = None
|
|
358
358
|
return list(spokes)
|
|
359
359
|
|
|
@@ -15,7 +15,7 @@ from __future__ import annotations
|
|
|
15
15
|
from collections.abc import Callable
|
|
16
16
|
from dataclasses import dataclass, field
|
|
17
17
|
|
|
18
|
-
from eth_typing import HexAddress
|
|
18
|
+
from eth_typing import HexAddress
|
|
19
19
|
from eth_utils import keccak
|
|
20
20
|
|
|
21
21
|
from ipor_fusion.fuses.hypercore import (
|
|
@@ -25,12 +25,12 @@ from ipor_fusion.fuses.hypercore import (
|
|
|
25
25
|
read_index_of,
|
|
26
26
|
)
|
|
27
27
|
from ipor_fusion.market_ids import IporFusionMarkets
|
|
28
|
-
from ipor_fusion.types import HyperCoreAsset, MarketId
|
|
28
|
+
from ipor_fusion.types import HyperCoreAsset, MarketId, parse_hex_address
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
@dataclass
|
|
32
32
|
class SubstrateInfo:
|
|
33
|
-
address: HexAddress =
|
|
33
|
+
address: HexAddress | None = None
|
|
34
34
|
raw_hex: str = ""
|
|
35
35
|
type_label: str = ""
|
|
36
36
|
is_error: bool = False
|
|
@@ -47,14 +47,10 @@ class SubstrateInfo:
|
|
|
47
47
|
# Slippage variant: [2 type chars][62 value chars]
|
|
48
48
|
|
|
49
49
|
|
|
50
|
-
def _hex_address(hex_digits: str) -> HexAddress:
|
|
51
|
-
return HexAddress(HexStr(f"0x{hex_digits}"))
|
|
52
|
-
|
|
53
|
-
|
|
54
50
|
def _decode_type_lshift160(hex_str: str, types: dict[int, str]) -> SubstrateInfo:
|
|
55
51
|
"""Decode type<<160 | address (Ebisu, Midas, Balancer, Velodrome)."""
|
|
56
52
|
type_byte = int(hex_str[22:24], 16)
|
|
57
|
-
addr =
|
|
53
|
+
addr = parse_hex_address(hex_str[24:])
|
|
58
54
|
label = types.get(type_byte, f"type={type_byte}")
|
|
59
55
|
return SubstrateInfo(address=addr, type_label=label)
|
|
60
56
|
|
|
@@ -67,13 +63,13 @@ def _decode_type_lshift248(hex_str: str, types: dict[int, str]) -> SubstrateInfo
|
|
|
67
63
|
return SubstrateInfo(
|
|
68
64
|
raw_hex=f"0x{hex_str}", type_label=label, extra={"slippage": str(value)}
|
|
69
65
|
)
|
|
70
|
-
addr =
|
|
66
|
+
addr = parse_hex_address(hex_str[24:])
|
|
71
67
|
return SubstrateInfo(address=addr, type_label=label)
|
|
72
68
|
|
|
73
69
|
|
|
74
70
|
def _decode_plain_address(hex_str: str) -> SubstrateInfo:
|
|
75
71
|
"""Decode zero-padded address: 12 zero bytes + 20 address bytes."""
|
|
76
|
-
return SubstrateInfo(address=
|
|
72
|
+
return SubstrateInfo(address=parse_hex_address(hex_str[24:]))
|
|
77
73
|
|
|
78
74
|
|
|
79
75
|
def _decode_morpho(hex_str: str) -> SubstrateInfo:
|
|
@@ -88,14 +84,14 @@ def _decode_uniswap_v4(hex_str: str) -> SubstrateInfo:
|
|
|
88
84
|
substrate-as-asset (12 zero bytes + address)."""
|
|
89
85
|
if hex_str[:24] == "0" * 24:
|
|
90
86
|
return SubstrateInfo(
|
|
91
|
-
address=
|
|
87
|
+
address=parse_hex_address(hex_str[24:]), type_label="uniswap_v4_token"
|
|
92
88
|
)
|
|
93
89
|
return SubstrateInfo(raw_hex=f"0x{hex_str}", type_label="uniswap_v4_pool_id")
|
|
94
90
|
|
|
95
91
|
|
|
96
92
|
def _decode_enso(hex_str: str) -> SubstrateInfo:
|
|
97
93
|
"""Decode address<<96 | selector<<64 (Enso)."""
|
|
98
|
-
addr =
|
|
94
|
+
addr = parse_hex_address(hex_str[0:40])
|
|
99
95
|
selector = f"0x{hex_str[40:48]}"
|
|
100
96
|
return SubstrateInfo(
|
|
101
97
|
address=addr, type_label="ENSO_TARGET", extra={"selector": selector}
|
|
@@ -104,7 +100,7 @@ def _decode_enso(hex_str: str) -> SubstrateInfo:
|
|
|
104
100
|
|
|
105
101
|
def _decode_dolomite(hex_str: str) -> SubstrateInfo:
|
|
106
102
|
"""Decode asset<<96 | subAccountId<<88 | canBorrow<<80 (Dolomite)."""
|
|
107
|
-
addr =
|
|
103
|
+
addr = parse_hex_address(hex_str[0:40])
|
|
108
104
|
sub_account_id = int(hex_str[40:42], 16)
|
|
109
105
|
can_borrow = (int(hex_str[42:44], 16) & 0x01) == 1
|
|
110
106
|
return SubstrateInfo(
|
|
@@ -131,7 +127,7 @@ def _decode_aave_v4(hex_str: str) -> SubstrateInfo:
|
|
|
131
127
|
return SubstrateInfo(raw_hex=f"0x{hex_str}", type_label=label)
|
|
132
128
|
flags = int(hex_str[50:52], 16)
|
|
133
129
|
return SubstrateInfo(
|
|
134
|
-
address=
|
|
130
|
+
address=parse_hex_address(hex_str[2:42]),
|
|
135
131
|
type_label="AAVE_V4_RESERVE",
|
|
136
132
|
extra={
|
|
137
133
|
"reserve_id": str(int(hex_str[42:50], 16)),
|
|
@@ -149,7 +145,7 @@ def _decode_euler_v2(hex_str: str) -> SubstrateInfo:
|
|
|
149
145
|
plain-address path silently produces a malformed address (last 20 bytes are
|
|
150
146
|
flag bytes + zero padding).
|
|
151
147
|
"""
|
|
152
|
-
addr =
|
|
148
|
+
addr = parse_hex_address(hex_str[0:40])
|
|
153
149
|
is_collateral = (int(hex_str[40:42], 16) & 0x01) == 1
|
|
154
150
|
can_borrow = (int(hex_str[42:44], 16) & 0x01) == 1
|
|
155
151
|
sub_account = f"0x{hex_str[44:46]}"
|
|
@@ -178,13 +174,13 @@ def _decode_async_action(hex_str: str) -> SubstrateInfo:
|
|
|
178
174
|
type_byte = int(hex_str[0:2], 16)
|
|
179
175
|
if type_byte == 0:
|
|
180
176
|
return SubstrateInfo(
|
|
181
|
-
address=
|
|
177
|
+
address=parse_hex_address(hex_str[2:42]),
|
|
182
178
|
type_label="ALLOWED_AMOUNT_TO_OUTSIDE",
|
|
183
179
|
extra={"amount": str(int(hex_str[42:64], 16))},
|
|
184
180
|
)
|
|
185
181
|
if type_byte == 1:
|
|
186
182
|
return SubstrateInfo(
|
|
187
|
-
address=
|
|
183
|
+
address=parse_hex_address(hex_str[16:56]),
|
|
188
184
|
type_label="ALLOWED_TARGETS",
|
|
189
185
|
extra={"selector": f"0x{hex_str[56:64]}"},
|
|
190
186
|
)
|
|
@@ -229,10 +225,10 @@ def _decode_external_state(hex_str: str) -> SubstrateInfo:
|
|
|
229
225
|
if type_byte == 0:
|
|
230
226
|
return SubstrateInfo(raw_hex=f"0x{hex_str}", type_label="UNDEFINED")
|
|
231
227
|
if label := _EXTERNAL_STATE_ADDRESS_TYPES.get(type_byte):
|
|
232
|
-
return SubstrateInfo(address=
|
|
228
|
+
return SubstrateInfo(address=parse_hex_address(hex_str[24:]), type_label=label)
|
|
233
229
|
if type_byte == 2:
|
|
234
230
|
return SubstrateInfo(
|
|
235
|
-
address=
|
|
231
|
+
address=parse_hex_address(hex_str[24:]),
|
|
236
232
|
type_label="TARGET",
|
|
237
233
|
extra={"selector": f"0x{hex_str[16:24]}"},
|
|
238
234
|
)
|
|
@@ -270,7 +266,7 @@ def _decode_crosschain(hex_str: str) -> SubstrateInfo:
|
|
|
270
266
|
is_error=True,
|
|
271
267
|
extra={"chain_id": str(chain_id)},
|
|
272
268
|
)
|
|
273
|
-
info = SubstrateInfo(address=
|
|
269
|
+
info = SubstrateInfo(address=parse_hex_address(hex_str[24:]), type_label=label)
|
|
274
270
|
if type_byte == 2:
|
|
275
271
|
info.extra = {"chain_id": str(chain_id)}
|
|
276
272
|
return info
|
|
@@ -330,7 +326,7 @@ def _decode_hypercore(hex_str: str) -> SubstrateInfo:
|
|
|
330
326
|
return _hypercore_invalid(hex_str, label)
|
|
331
327
|
if type_byte == 1:
|
|
332
328
|
return SubstrateInfo(
|
|
333
|
-
address=
|
|
329
|
+
address=parse_hex_address(hex_str[24:]),
|
|
334
330
|
type_label=label,
|
|
335
331
|
extra={"token_index": str(int(hex_str[8:24], 16))},
|
|
336
332
|
)
|
|
@@ -351,10 +347,10 @@ def _decode_hypercore(hex_str: str) -> SubstrateInfo:
|
|
|
351
347
|
extra["read_index"] = str(read_index_of(asset))
|
|
352
348
|
return SubstrateInfo(raw_hex=f"0x{hex_str}", type_label=label, extra=extra)
|
|
353
349
|
if type_byte == 3:
|
|
354
|
-
return SubstrateInfo(address=
|
|
350
|
+
return SubstrateInfo(address=parse_hex_address(hex_str[24:]), type_label=label)
|
|
355
351
|
if type_byte == 4:
|
|
356
352
|
return SubstrateInfo(
|
|
357
|
-
address=
|
|
353
|
+
address=parse_hex_address(hex_str[24:]),
|
|
358
354
|
type_label=label,
|
|
359
355
|
extra={"max_fee_rate_decibps": str(int(hex_str[8:24], 16))},
|
|
360
356
|
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from typing import ClassVar, Literal, NewType, TypeAlias
|
|
3
3
|
|
|
4
|
-
from eth_typing import ChecksumAddress, HexStr
|
|
4
|
+
from eth_typing import ChecksumAddress, HexAddress, HexStr
|
|
5
5
|
|
|
6
6
|
Amount = NewType("Amount", int)
|
|
7
7
|
Shares = NewType("Shares", int)
|
|
@@ -131,3 +131,27 @@ def parse_morpho_market_id(value: str | bytes) -> MorphoBlueMarketId:
|
|
|
131
131
|
if len(digits) != 64 or any(c not in "0123456789abcdef" for c in digits):
|
|
132
132
|
raise ValueError(f"invalid Morpho market ID (expected 32-byte hex): {value}")
|
|
133
133
|
return MorphoBlueMarketId("0x" + digits)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _hex_digits(value: str | bytes, size: int, what: str) -> str:
|
|
137
|
+
if isinstance(value, bytes):
|
|
138
|
+
if len(value) != size:
|
|
139
|
+
raise ValueError(f"invalid {what} (expected {size} bytes): {value!r}")
|
|
140
|
+
return value.hex()
|
|
141
|
+
digits = value.strip().removeprefix("0x").removeprefix("0X").lower()
|
|
142
|
+
if len(digits) != 2 * size or any(c not in "0123456789abcdef" for c in digits):
|
|
143
|
+
raise ValueError(f"invalid {what} (expected {size}-byte hex): {value}")
|
|
144
|
+
return digits
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def parse_hex_address(value: str | bytes) -> HexAddress:
|
|
148
|
+
"""An address as ``0x`` and 40 lowercase hex digits, from 20 raw bytes or hex
|
|
149
|
+
in any spelling; raises ``ValueError`` on anything else. For a checksummed
|
|
150
|
+
address use ``Web3.to_checksum_address``."""
|
|
151
|
+
return HexAddress(HexStr("0x" + _hex_digits(value, 20, "address")))
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def parse_tx_hash(value: str | bytes) -> TxHash:
|
|
155
|
+
"""A transaction hash as ``0x`` and 64 lowercase hex digits, from 32 raw bytes
|
|
156
|
+
or hex in any spelling; raises ``ValueError`` on anything else."""
|
|
157
|
+
return TxHash(HexStr("0x" + _hex_digits(value, 32, "transaction hash")))
|
|
@@ -110,13 +110,13 @@ class VaultState(Protocol):
|
|
|
110
110
|
@property
|
|
111
111
|
def underlying_balance_on_vault(self) -> int: ...
|
|
112
112
|
@property
|
|
113
|
-
def price_oracle_addr(self) ->
|
|
113
|
+
def price_oracle_addr(self) -> ChecksumAddress: ...
|
|
114
114
|
@property
|
|
115
115
|
def balance_fuses(self) -> Sequence[BalanceFuse]: ...
|
|
116
116
|
@property
|
|
117
117
|
def market_substrates(self) -> Mapping[MarketId, Sequence[bytes]] | None: ...
|
|
118
118
|
@property
|
|
119
|
-
def fuse_markets(self) -> Mapping[
|
|
119
|
+
def fuse_markets(self) -> Mapping[ChecksumAddress, MarketId] | None: ...
|
|
120
120
|
@property
|
|
121
121
|
def dependency_graph(self) -> Mapping[MarketId, Sequence[MarketId]] | None: ...
|
|
122
122
|
@property
|