ipor-fusion 4.0.0.dev141__tar.gz → 4.0.0.dev146__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.dev141 → ipor_fusion-4.0.0.dev146}/AGENTS.md +2 -1
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/MIGRATION_4.md +45 -26
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +2 -2
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +2 -1
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_cmd.py +3 -1
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fusion_factory.py +9 -8
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/simulation.py +3 -3
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/contracts.py +5 -2
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/lane.py +2 -2
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/contracts.py +8 -4
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/lane.py +17 -8
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/contracts.py +3 -2
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/lane.py +2 -2
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/mcp/server.py +1 -1
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/lending_health.py +1 -1
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/oracle_mapping.py +3 -2
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/validation.py +16 -16
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_data.py +14 -4
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_commands.py +9 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_oracle_mapping.py +4 -4
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_docs_typing.py +5 -1
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_mcp_server.py +2 -2
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_oracle_mapping.py +3 -3
- ipor_fusion-4.0.0.dev146/tests/test_vault_data_block.py +34 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/README.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_public_api.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/tests/typed_client/rejected.py +0 -0
- {ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/uv.lock +0 -0
|
@@ -441,7 +441,8 @@ are not validated.
|
|
|
441
441
|
## Domain rules (verified against the contracts)
|
|
442
442
|
|
|
443
443
|
- `fetch_vault_data(ctx, vault, *, block=, lending=, metadata=)` is the snapshot:
|
|
444
|
-
it resolves one block (``block``, else
|
|
444
|
+
it resolves one block (``block``, else `ctx.default_block` with a tag or hash resolved to its
|
|
445
|
+
number, else latest),
|
|
445
446
|
runs every read on `ctx.at_block(block)` (log scans end there too) and returns
|
|
446
447
|
everything validation and the ``vault info`` document need, so neither reads the
|
|
447
448
|
chain. The chain is `ctx.chain_id`; ``lending=False`` skips lending health, the
|
|
@@ -6,10 +6,11 @@ the details, and each change is described once, in its section.
|
|
|
6
6
|
|
|
7
7
|
## Start here
|
|
8
8
|
|
|
9
|
-
> **
|
|
10
|
-
> `
|
|
11
|
-
>
|
|
12
|
-
>
|
|
9
|
+
> **Most 3.x calls fail only when the line runs.** A removed import
|
|
10
|
+
> (`ipor_fusion.fuses.crosschain`, `NavMark`, the 3.x cache functions) fails at
|
|
11
|
+
> import, but `PlasmaVault(ctx, address)`, `ERC20(ctx, token)` or any other
|
|
12
|
+
> `Wrapper(ctx, ...)` raises `TypeError` only when that line executes, and so does
|
|
13
|
+
> `call.call()` without a context. A service that wraps its reads in a broad `except Exception` degrades
|
|
13
14
|
> silently (empty values, skipped vaults) instead of failing. Before you deploy:
|
|
14
15
|
>
|
|
15
16
|
> - search for wrappers built with a context (`(ctx,`, `(self.ctx,`, `(self._ctx,`)
|
|
@@ -93,7 +94,7 @@ placeholder wrapper.
|
|
|
93
94
|
`aggregate3(calls)` still returns the raw `Call`), `VaultSimulator`,
|
|
94
95
|
`CrosschainSimulator` and `OracleMappingReader(ctx, oracle)`.
|
|
95
96
|
- Resolvers that probe the chain stay eager and return context-free wrappers:
|
|
96
|
-
`price_oracle_middleware(ctx,
|
|
97
|
+
`price_oracle_middleware(ctx, address)`, `resolve_access_manager(ctx, vault)`,
|
|
97
98
|
`ExternalStateExecutor.for_vault(ctx, vault)`. A resolved oracle carries the ABI
|
|
98
99
|
found on that chain and block; resolve again for another one.
|
|
99
100
|
- Crosschain lanes own both contexts: `CcipLane` / `StargateLane` take `hub_ctx=` and
|
|
@@ -112,9 +113,9 @@ placeholder wrapper.
|
|
|
112
113
|
do not see a CCIP recall or tell a parked command from a pending one. `CrosschainTransport.executor(address)`
|
|
113
114
|
and `.dispatcher(address)` no longer take a context.
|
|
114
115
|
- Chain-bound decoding takes the chain explicitly:
|
|
115
|
-
`ExternalStateExecutor.pending_proposals(
|
|
116
|
+
`ExternalStateExecutor.pending_proposals(balance_account, *, chain_id)`,
|
|
116
117
|
`parse_balance_proposed(log, *, chain_id)` and
|
|
117
|
-
`find_balance_proposed(logs,
|
|
118
|
+
`find_balance_proposed(logs, balance_account=None, *, chain_id)` require it (3.x fell back
|
|
118
119
|
to the wrapper's context). The decoder captures it, so `.call(ctx)`, `Multicall3`
|
|
119
120
|
and `VaultSimulator.observe` stamp the same hash for the same bytes, whatever
|
|
120
121
|
context executes them. Pass `ctx.chain_id` for the chain you read from.
|
|
@@ -133,7 +134,7 @@ placeholder wrapper.
|
|
|
133
134
|
| `call.build_transaction(block=b)`, `call.estimate_gas(block=b)` | `call.build_transaction(ctx, block=b)`, `call.estimate_gas(ctx, block=b)` |
|
|
134
135
|
| `call.ctx` | gone: keep the context yourself |
|
|
135
136
|
| `Multicall3(ctx, address)` | `Multicall3(ctx, address=address)` |
|
|
136
|
-
| `executor.pending_proposals(
|
|
137
|
+
| `executor.pending_proposals(balance_account)` | `executor.pending_proposals(balance_account, chain_id=ctx.chain_id)` |
|
|
137
138
|
| `executor.parse_balance_proposed(log)` / `find_balance_proposed(logs)` | `...(log, chain_id=...)` / `...(logs, chain_id=...)` |
|
|
138
139
|
| `CcipLane(executor=, dispatcher=, spoke_chain_id=, ...)` | `CcipLane(hub_ctx=, spoke_ctx=, executor=, dispatcher=, ...)` (same for `StargateLane`) |
|
|
139
140
|
| `transport.executor(ctx, address)` / `transport.dispatcher(ctx, address)` | `transport.executor(address)` / `transport.dispatcher(address)` |
|
|
@@ -173,7 +174,8 @@ The vault read is one pinned snapshot, and the chain is always the context's:
|
|
|
173
174
|
|
|
174
175
|
- `fetch_vault_data(ctx, vault, *, block=None, lending=True, metadata=True)` takes
|
|
175
176
|
the vault address (not a `PlasmaVault`) and no `chain_id`. It resolves one block
|
|
176
|
-
(`block`, else
|
|
177
|
+
(`block`, else `ctx.default_block`, with a `safe` / `finalized` tag or a block hash
|
|
178
|
+
resolved to its number, else the latest) and runs every
|
|
177
179
|
read, log scans included, on `ctx.at_block(block)`; `ctx` is not modified. In 3.x
|
|
178
180
|
`block_number` only selected the block reported in `VaultData`, and the reads ran
|
|
179
181
|
wherever `ctx` pointed. The old `chain_id=0` switch is `lending=False`;
|
|
@@ -189,8 +191,7 @@ The vault read is one pinned snapshot, and the chain is always the context's:
|
|
|
189
191
|
no longer takes `resolve_symbol`. `metadata=True` names the ERC20 holdings in the
|
|
190
192
|
result and its findings. `validate_vault_state(state)` is pure: a custom
|
|
191
193
|
`VaultState` also provides `vault`, `chain_id`, `market_balances`, `erc20` and the
|
|
192
|
-
queue's `shares_to_release_assets`.
|
|
193
|
-
`VaultData.erc20`.
|
|
194
|
+
queue's `shares_to_release_assets`.
|
|
194
195
|
- `build_vault_info_json(data, *, resolve_name=None)` renders from the snapshot and
|
|
195
196
|
reads nothing; the chain and its label come from `data.chain_id`. Without
|
|
196
197
|
`resolve_name` it names no contract (see
|
|
@@ -280,7 +281,8 @@ fails at run time:
|
|
|
280
281
|
zero-address placeholder. `execute()` without `vault` and `alpha` raises
|
|
281
282
|
`ValueError`, as does `execute_call` without `from_` or `alpha`.
|
|
282
283
|
- `fetch_unpriceable_priced_tokens(ctx, *, price_oracle, underlying, balance_fuses,
|
|
283
|
-
market_substrates, morpho_positions)` takes everything after `ctx` by keyword
|
|
284
|
+
market_substrates, morpho_positions)` takes everything after `ctx` by keyword, and
|
|
285
|
+
its `oracle_address` parameter is renamed `price_oracle`.
|
|
284
286
|
- `get_contract_name(chain_id, address, *, api_key=None, cache=None)` and
|
|
285
287
|
`get_deployment_tx(chain_id, address, *, api_key=None)` take `api_key` by keyword.
|
|
286
288
|
- `build_morpho_blue_market_json(*, market_id, chain_id, params, state, rates,
|
|
@@ -288,6 +290,8 @@ fails at run time:
|
|
|
288
290
|
keyword.
|
|
289
291
|
- `encode_oft_compose_msg(*, nonce=, src_eid=, amount_ld=, compose_msg=)` takes
|
|
290
292
|
keyword arguments only.
|
|
293
|
+
- `build_oracle_mapping(ctx, vault, *, effective_block, max_depth=6)` takes
|
|
294
|
+
`effective_block` and `max_depth` by keyword.
|
|
291
295
|
- The vault parameter is named `vault` throughout: `validate_vault`,
|
|
292
296
|
`fetch_deployment_info`, `fetch_vault_lending_health`, `build_oracle_mapping`,
|
|
293
297
|
`read_external_state`, `ExternalStateExecutor.for_vault`, `read_hypercore_nav`,
|
|
@@ -346,9 +350,11 @@ is the wrong one.
|
|
|
346
350
|
- The Morpho API client raises `MorphoApiError` for every answer it cannot use and
|
|
347
351
|
every transport failure, never `KeyError`, `TypeError` or `ValueError`:
|
|
348
352
|
- a required market id or address (market and V1 allocation ids, V1 flow-cap ids,
|
|
349
|
-
vault/asset/owner/token/oracle/IRM
|
|
350
|
-
|
|
351
|
-
|
|
353
|
+
vault/asset/owner/token/oracle/IRM addresses) that is absent or invalid; an
|
|
354
|
+
optional address (curator, guardian, fee recipients, ...) that is absent or `""`
|
|
355
|
+
reads as `None`, and raises only when present and invalid; an allocator or
|
|
356
|
+
sentinel entry without an address is skipped, and one with an invalid address
|
|
357
|
+
raises;
|
|
352
358
|
- any other answer it cannot read (a missing key such as a `loanAsset` without
|
|
353
359
|
`address`, a value of the wrong type, a body that is not a JSON object);
|
|
354
360
|
- any `OSError` or `http.client.HTTPException` while fetching (it caught only
|
|
@@ -431,8 +437,8 @@ are cached in a `ContractCache`, injected instead of always written to `~/.cache
|
|
|
431
437
|
explicitly (default: the file cache); pass `cache=ctx.cache` to share the
|
|
432
438
|
context's policy. The CLI's text and JSON output name contracts through the
|
|
433
439
|
context's cache.
|
|
434
|
-
- `build_vault_info_json(data)` without `resolve_name` names no contract (
|
|
435
|
-
`contract`
|
|
440
|
+
- `build_vault_info_json(data)` without `resolve_name` names no contract (fuse and
|
|
441
|
+
balance-fuse entries show `contract` as `"?"`, substrate entries omit it) instead of reading names from the on-disk cache; pass
|
|
436
442
|
`resolve_name=partial(get_contract_name, chain_id, api_key=..., cache=ctx.cache)`
|
|
437
443
|
for the CLI's document.
|
|
438
444
|
- `ipor_fusion.cache` is a public module now and exports `ContractCache`,
|
|
@@ -533,13 +539,18 @@ converted amounts `Amount`. A custom `VaultState` annotates the same.
|
|
|
533
539
|
`PlasmaVault.total_supply()`, `balance_of()` and `get_total_supply_cap()` return
|
|
534
540
|
`Shares` (vault shares), and `transfer` / `approve` / `transfer_from` /
|
|
535
541
|
`set_total_supply_cap` take `Shares`; `ERC20` keeps `Amount`.
|
|
542
|
+
`Reconciliation` amounts (`balance_fuses_total`, `underlying_on_vault`,
|
|
543
|
+
`erc20_direct_total`, `sum`, `on_chain_total_assets`, `delta`,
|
|
544
|
+
`pending_withdrawals`, `implied_market_total`, `market_storage_divergence`) are
|
|
545
|
+
`Amount`. `FusionInstance.asset_decimals` / `underlying_token_decimals` are
|
|
546
|
+
`Decimals`. `VaultSimulator.current_time` is a `Timestamp`.
|
|
536
547
|
|
|
537
548
|
**Vault data and helpers.** `ensure_supported_chain` takes `ChainId`.
|
|
538
549
|
`fetch_unpriceable_priced_tokens` takes the oracle and underlying as
|
|
539
550
|
`ChecksumAddress`. `resolve_token_symbol`, `resolve_token_decimals`,
|
|
540
551
|
`get_contract_name` and `get_deployment_tx` take `HexAddress` (a checksum address
|
|
541
|
-
fits), and the `resolve_name`
|
|
542
|
-
|
|
552
|
+
fits), and the `resolve_name` callback receives one (a callback typed for `str`
|
|
553
|
+
still fits). Market-keyed data is keyed by `MarketId`:
|
|
543
554
|
`VaultData.market_substrates`, `dependency_graph`, `morpho_positions`,
|
|
544
555
|
`aave_positions`, `market_balances`; the `VaultState` protocol,
|
|
545
556
|
`fetch_vault_lending_health`, `fetch_unpriceable_priced_tokens` and the
|
|
@@ -563,8 +574,8 @@ The Uniswap V3 / Ramses V2 position events' `version`, `sender` and `recipient`
|
|
|
563
574
|
`MarketId`; `Erc20Holding.address` is `HexAddress`, and `SubstrateInfo.address` is
|
|
564
575
|
`HexAddress | None`. `LegacyPriceOracleMiddleware` takes `base_currency_decimals:
|
|
565
576
|
Decimals`, and `PriceOracleMiddleware.base_currency_decimals()` returns
|
|
566
|
-
`Call[Decimals]`. `get_logs_adaptive(chain_id=)`
|
|
567
|
-
`ChainId`; `quote_ccip_native_fee(block=)` and
|
|
577
|
+
`Call[Decimals]`. `get_logs_adaptive(chain_id=)` takes `ChainId | None` and
|
|
578
|
+
`LogSource.get_logs` a `ChainId`; `quote_ccip_native_fee(block=)` and
|
|
568
579
|
`OracleMappingReader.asset_source_events` take a `BlockIdentifier`.
|
|
569
580
|
|
|
570
581
|
**Address roles.** `PlasmaVault(address)`,
|
|
@@ -599,7 +610,8 @@ by `ChainId` (`HYPEREVM_CHAIN_ID` is one) and `explorer.SUPPORTED_CHAINS` is a
|
|
|
599
610
|
type-checks; `PUBLIC_ALLOCATOR_ADDRESSES` values are `ChecksumAddress`.
|
|
600
611
|
|
|
601
612
|
**Markets, substrates and access.** Every `IporFusionMarkets` member is a `MarketId`.
|
|
602
|
-
`
|
|
613
|
+
`market_name` and `format_market_label` take `MarketId`, `decode_substrate` a
|
|
614
|
+
`MarketId | None`.
|
|
603
615
|
`AccessManager.has_role`, `grant_role`, `revoke_role` and `read_accounts_with_role`
|
|
604
616
|
take `RoleId | Roles`; `RoleAccount.role_id` is `RoleId`.
|
|
605
617
|
|
|
@@ -627,7 +639,12 @@ on CCIP, `active_return` → `OperationId`, `asset_id`, `tracked_position_set_ha
|
|
|
627
639
|
`CcipObservation`, `OutboundMessage`, `CcipMessageSent`, `Any2EVMMessage`,
|
|
628
640
|
`VerifierResult`, `Packet.guid`, `TaxiMessage`, `StargateChain`; and the helpers
|
|
629
641
|
`fetch_verifier_result(message_id=)`, `lz_receive_calldata(guid=)` and
|
|
630
|
-
`lz_compose_calldata(guid=)` take a `MessageId`.
|
|
642
|
+
`lz_compose_calldata(guid=)` take a `MessageId`. Lane times are typed:
|
|
643
|
+
`last_approved_observed_at()` returns a `Timestamp` and `staleness_max()` (with
|
|
644
|
+
`STALENESS_MAX` / `BALANCE_STALENESS_MAX` on the executors) a `Period`, and so do
|
|
645
|
+
the `LaneHubState` fields; `attestation(remote_timestamp=, expiry=)` and
|
|
646
|
+
`BalanceObservation` take `Timestamp`, `needs_attestation(now=, margin=)` a
|
|
647
|
+
`Timestamp` and a `Period`. Decoded event values
|
|
631
648
|
(`ccip_events` → `CcipEvent.values`) stay a generic mapping: convert a value
|
|
632
649
|
before passing it on.
|
|
633
650
|
|
|
@@ -654,20 +671,22 @@ HyperCore ids; `HyperCorePerpAssetInfo`, `HyperCorePerpMarket`, `HyperCoreSpotLe
|
|
|
654
671
|
|
|
655
672
|
**External state.** `ExternalStateExecutor.proposal_hash` returns and `confirm_balance`
|
|
656
673
|
takes a `ProposalHash`; `BalanceProposal.proposal_hash` is a `ProposalHash`;
|
|
657
|
-
`ExternalStateEvent.transaction_hash` is a `TxHash`.
|
|
674
|
+
`ExternalStateEvent.transaction_hash` is a `TxHash | None`.
|
|
658
675
|
`ExternalStateVaultState.last_checked_custodian_timestamp`,
|
|
659
676
|
`BalanceFuseSnapshot.last_custodian_update_timestamp`, `BalanceProposal.proposed_at`,
|
|
660
677
|
`last_updated()` and `get_oldest_update_timestamp()` are web3's `Timestamp`, and
|
|
661
678
|
`ExternalStateExecutor.proposal_hash(proposed_at=)` takes one.
|
|
662
679
|
|
|
663
|
-
**Errors and explorer.** `TransactionError(tx_hash=)` takes a `TxHash`,
|
|
680
|
+
**Errors and explorer.** `TransactionError(tx_hash=)` takes a `TxHash | None`,
|
|
664
681
|
`LogScanError(address=)` a `ChecksumAddress`; `get_revert_reason` takes a `TxHash`;
|
|
665
682
|
`get_deployment_tx` returns a `TxHash` (a malformed hash from Etherscan is reported
|
|
666
683
|
as the error `malformed-tx-hash`).
|
|
667
684
|
|
|
668
685
|
**MCP response models** (Python constructors only; the JSON schemas are unchanged
|
|
669
686
|
except as listed under [Behavior changes](#behavior-changes)): `chain_id` fields are
|
|
670
|
-
`ChainId`, `role_id` `RoleId`, `market_id` `MarketId
|
|
687
|
+
`ChainId`, `role_id` `RoleId`, `market_id` `MarketId` (except
|
|
688
|
+
`LendingMarketHealth.market_id`, which stays `str | int`: a Morpho market id is a
|
|
689
|
+
string). Calling an MCP tool function
|
|
671
690
|
directly from Python takes `ChainId`.
|
|
672
691
|
|
|
673
692
|
## Behavior changes
|
|
@@ -68,7 +68,7 @@ from typing import Any, NamedTuple
|
|
|
68
68
|
from eth_abi.abi import encode as abi_encode
|
|
69
69
|
from eth_utils import keccak
|
|
70
70
|
from web3 import Web3
|
|
71
|
-
from web3.types import BlockIdentifier, RPCEndpoint
|
|
71
|
+
from web3.types import BlockIdentifier, RPCEndpoint, Timestamp
|
|
72
72
|
|
|
73
73
|
from ipor_fusion import (
|
|
74
74
|
ERC20,
|
|
@@ -791,7 +791,7 @@ def _attest(flow: _Tail, tag: str, observation_label: str, *, hub_idle: int = 0)
|
|
|
791
791
|
observation,
|
|
792
792
|
remote_block=flow.spoke.current_block_number,
|
|
793
793
|
remote_timestamp=flow.spoke.current_time,
|
|
794
|
-
expiry=flow.hub.current_time + PROPOSAL_TTL,
|
|
794
|
+
expiry=Timestamp(flow.hub.current_time + PROPOSAL_TTL),
|
|
795
795
|
)
|
|
796
796
|
# SIMULATION ONLY: two keyless addresses driven from one process; live
|
|
797
797
|
# they are two signers, which is the point of the two-key design.
|
|
@@ -66,6 +66,7 @@ import sys
|
|
|
66
66
|
from typing import NamedTuple
|
|
67
67
|
|
|
68
68
|
from web3 import Web3
|
|
69
|
+
from web3.types import Timestamp
|
|
69
70
|
|
|
70
71
|
from ipor_fusion import (
|
|
71
72
|
ERC20,
|
|
@@ -431,7 +432,7 @@ def _attest(flow: _Flow, tag: str, observation_label: str, *, hub_idle: int = 0)
|
|
|
431
432
|
observation,
|
|
432
433
|
remote_block=flow.spoke.current_block_number,
|
|
433
434
|
remote_timestamp=flow.spoke.current_time,
|
|
434
|
-
expiry=flow.hub.current_time + PROPOSAL_TTL,
|
|
435
|
+
expiry=Timestamp(flow.hub.current_time + PROPOSAL_TTL),
|
|
435
436
|
)
|
|
436
437
|
# SIMULATION ONLY: the proposer and the approver are two addresses with no
|
|
437
438
|
# keys here, driven from one process. Live they are two separate signers,
|
|
@@ -449,7 +449,9 @@ def oracle_mapping(
|
|
|
449
449
|
raise click.UsageError(str(exc)) from exc
|
|
450
450
|
|
|
451
451
|
try:
|
|
452
|
-
mapping = build_oracle_mapping(
|
|
452
|
+
mapping = build_oracle_mapping(
|
|
453
|
+
ctx, vault_address, effective_block=effective_block, max_depth=max_depth
|
|
454
|
+
)
|
|
453
455
|
except UnsupportedVaultVersionError as exc:
|
|
454
456
|
raise click.ClickException(str(exc)) from exc
|
|
455
457
|
|
{ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fusion_factory.py
RENAMED
|
@@ -35,6 +35,7 @@ from web3.types import TxReceipt
|
|
|
35
35
|
from ipor_fusion.core.contract import Call, ContractWrapper
|
|
36
36
|
from ipor_fusion.types import (
|
|
37
37
|
AccessManagerAddress,
|
|
38
|
+
Decimals,
|
|
38
39
|
Period,
|
|
39
40
|
PlasmaVaultAddress,
|
|
40
41
|
parse_access_manager_address,
|
|
@@ -64,10 +65,10 @@ class FusionInstance:
|
|
|
64
65
|
version: int
|
|
65
66
|
asset_name: str
|
|
66
67
|
asset_symbol: str
|
|
67
|
-
asset_decimals:
|
|
68
|
+
asset_decimals: Decimals
|
|
68
69
|
underlying_token: ChecksumAddress
|
|
69
70
|
underlying_token_symbol: str
|
|
70
|
-
underlying_token_decimals:
|
|
71
|
+
underlying_token_decimals: Decimals
|
|
71
72
|
initial_owner: ChecksumAddress
|
|
72
73
|
plasma_vault: PlasmaVaultAddress
|
|
73
74
|
plasma_vault_base: ChecksumAddress
|
|
@@ -118,10 +119,10 @@ _INSTANCE_FIELDS: dict[str, Callable[[Any], Any]] = {
|
|
|
118
119
|
"version": _integer,
|
|
119
120
|
"asset_name": _text,
|
|
120
121
|
"asset_symbol": _text,
|
|
121
|
-
"asset_decimals": _integer,
|
|
122
|
+
"asset_decimals": lambda value: Decimals(_integer(value)),
|
|
122
123
|
"underlying_token": _address,
|
|
123
124
|
"underlying_token_symbol": _text,
|
|
124
|
-
"underlying_token_decimals": _integer,
|
|
125
|
+
"underlying_token_decimals": lambda value: Decimals(_integer(value)),
|
|
125
126
|
"initial_owner": _address,
|
|
126
127
|
"plasma_vault": lambda value: parse_plasma_vault_address(_text(value)),
|
|
127
128
|
"plasma_vault_base": _address,
|
|
@@ -185,10 +186,10 @@ def _fusion_instance_decoder(values: tuple) -> FusionInstance:
|
|
|
185
186
|
version=version,
|
|
186
187
|
asset_name=asset_name,
|
|
187
188
|
asset_symbol=asset_symbol,
|
|
188
|
-
asset_decimals=asset_decimals,
|
|
189
|
+
asset_decimals=Decimals(asset_decimals),
|
|
189
190
|
underlying_token=addr(underlying_token),
|
|
190
191
|
underlying_token_symbol=underlying_token_symbol,
|
|
191
|
-
underlying_token_decimals=underlying_token_decimals,
|
|
192
|
+
underlying_token_decimals=Decimals(underlying_token_decimals),
|
|
192
193
|
initial_owner=addr(initial_owner),
|
|
193
194
|
plasma_vault=PlasmaVaultAddress(addr(plasma_vault)),
|
|
194
195
|
plasma_vault_base=addr(plasma_vault_base),
|
|
@@ -347,10 +348,10 @@ class FusionFactory(ContractWrapper):
|
|
|
347
348
|
version=int(values[1]),
|
|
348
349
|
asset_name=values[2],
|
|
349
350
|
asset_symbol=values[3],
|
|
350
|
-
asset_decimals=int(values[4]),
|
|
351
|
+
asset_decimals=Decimals(int(values[4])),
|
|
351
352
|
underlying_token=Web3.to_checksum_address(values[5]),
|
|
352
353
|
underlying_token_symbol=values[6],
|
|
353
|
-
underlying_token_decimals=int(values[7]),
|
|
354
|
+
underlying_token_decimals=Decimals(int(values[7])),
|
|
354
355
|
initial_owner=Web3.to_checksum_address(values[8]),
|
|
355
356
|
plasma_vault=PlasmaVaultAddress(Web3.to_checksum_address(values[9])),
|
|
356
357
|
plasma_vault_base=Web3.to_checksum_address(values[10]),
|
|
@@ -10,7 +10,7 @@ from eth_typing import ChecksumAddress
|
|
|
10
10
|
from eth_utils import keccak
|
|
11
11
|
from hexbytes import HexBytes
|
|
12
12
|
from web3 import Web3
|
|
13
|
-
from web3.types import BlockIdentifier, Nonce, RPCEndpoint
|
|
13
|
+
from web3.types import BlockIdentifier, Nonce, RPCEndpoint, Timestamp
|
|
14
14
|
from web3.utils.address import get_create_address
|
|
15
15
|
|
|
16
16
|
from ipor_fusion.core.contract import Call, _encode_calldata
|
|
@@ -221,13 +221,13 @@ class VaultSimulator:
|
|
|
221
221
|
return any(block.calls for block in self._blocks)
|
|
222
222
|
|
|
223
223
|
@property
|
|
224
|
-
def current_time(self) ->
|
|
224
|
+
def current_time(self) -> Timestamp:
|
|
225
225
|
"""Timestamp of the latest sent block or an explicit pending time.
|
|
226
226
|
|
|
227
227
|
A pending block without an explicit time will run 12 seconds later
|
|
228
228
|
once it contains a call.
|
|
229
229
|
"""
|
|
230
|
-
return self._current_time()
|
|
230
|
+
return Timestamp(self._current_time())
|
|
231
231
|
|
|
232
232
|
@property
|
|
233
233
|
def current_block_number(self) -> int:
|
{ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/contracts.py
RENAMED
|
@@ -26,6 +26,7 @@ from ipor_fusion.types import (
|
|
|
26
26
|
CommandId,
|
|
27
27
|
MessageId,
|
|
28
28
|
OperationId,
|
|
29
|
+
Period,
|
|
29
30
|
PlasmaVaultAddress,
|
|
30
31
|
PositionSetHash,
|
|
31
32
|
ProposalId,
|
|
@@ -143,8 +144,10 @@ class CcipCrosschainExecutor(CrosschainExecutor):
|
|
|
143
144
|
def decimal_conversion_rate(self) -> Call[int]:
|
|
144
145
|
return self._view("DECIMAL_CONVERSION_RATE()", output_types=["uint256"])
|
|
145
146
|
|
|
146
|
-
def balance_staleness_max(self) -> Call[
|
|
147
|
-
return self._view(
|
|
147
|
+
def balance_staleness_max(self) -> Call[Period]:
|
|
148
|
+
return self._view(
|
|
149
|
+
"BALANCE_STALENESS_MAX()", output_types=["uint256"], decoder=Period
|
|
150
|
+
)
|
|
148
151
|
|
|
149
152
|
def ccip_route(self, chain_id: ChainId) -> Call[CcipRouteConfig]:
|
|
150
153
|
return self._view(
|
{ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/lane.py
RENAMED
|
@@ -22,7 +22,7 @@ from ipor_fusion.crosschain.fuses.ccip import (
|
|
|
22
22
|
)
|
|
23
23
|
from ipor_fusion.crosschain.lane import CrosschainLane, LaneFuses, LaneObservation
|
|
24
24
|
from ipor_fusion.crosschain.messages import CommandStatus, CrosschainTransportKind
|
|
25
|
-
from ipor_fusion.types import Amount, ProposalId
|
|
25
|
+
from ipor_fusion.types import Amount, Period, ProposalId
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class CcipLane(CrosschainLane):
|
|
@@ -89,7 +89,7 @@ class CcipLane(CrosschainLane):
|
|
|
89
89
|
),
|
|
90
90
|
)
|
|
91
91
|
|
|
92
|
-
def staleness_max(self) -> Call[
|
|
92
|
+
def staleness_max(self) -> Call[Period]:
|
|
93
93
|
return self.executor.balance_staleness_max()
|
|
94
94
|
|
|
95
95
|
def default_send(self, *, token: bool) -> CcipSendParams:
|
{ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/contracts.py
RENAMED
|
@@ -16,6 +16,7 @@ from dataclasses import dataclass
|
|
|
16
16
|
|
|
17
17
|
from eth_typing import ChecksumAddress
|
|
18
18
|
from web3 import Web3
|
|
19
|
+
from web3.types import Timestamp
|
|
19
20
|
|
|
20
21
|
from ipor_fusion.core.contract import Call, ContractWrapper
|
|
21
22
|
from ipor_fusion.crosschain.messages import CommandStatus
|
|
@@ -42,8 +43,8 @@ class BalanceObservation:
|
|
|
42
43
|
settled_balance: Amount
|
|
43
44
|
state_version: int
|
|
44
45
|
remote_block: int
|
|
45
|
-
remote_timestamp:
|
|
46
|
-
expiry:
|
|
46
|
+
remote_timestamp: Timestamp
|
|
47
|
+
expiry: Timestamp
|
|
47
48
|
tracked_position_set_hash: PositionSetHash
|
|
48
49
|
|
|
49
50
|
def as_tuple(self) -> tuple:
|
|
@@ -160,9 +161,12 @@ class CrosschainExecutor(ContractWrapper):
|
|
|
160
161
|
def chain_blocked(self, chain_id: ChainId) -> Call[bool]:
|
|
161
162
|
return self._view("chainBlocked(uint256)", chain_id, output_types=["bool"])
|
|
162
163
|
|
|
163
|
-
def last_approved_observed_at(self, chain_id: ChainId) -> Call[
|
|
164
|
+
def last_approved_observed_at(self, chain_id: ChainId) -> Call[Timestamp]:
|
|
164
165
|
return self._view(
|
|
165
|
-
"lastApprovedObservedAt(uint256)",
|
|
166
|
+
"lastApprovedObservedAt(uint256)",
|
|
167
|
+
chain_id,
|
|
168
|
+
output_types=["uint64"],
|
|
169
|
+
decoder=Timestamp,
|
|
166
170
|
)
|
|
167
171
|
|
|
168
172
|
def approve_balance(self, proposal_id: ProposalId) -> Call[None]:
|
|
@@ -34,6 +34,7 @@ from typing import Any, ClassVar, cast
|
|
|
34
34
|
|
|
35
35
|
from eth_abi import decode
|
|
36
36
|
from eth_typing import ChecksumAddress
|
|
37
|
+
from web3.types import Timestamp
|
|
37
38
|
|
|
38
39
|
from ipor_fusion.core.context import Web3Context
|
|
39
40
|
from ipor_fusion.core.contract import Call
|
|
@@ -52,7 +53,14 @@ from ipor_fusion.crosschain.fuses.base import (
|
|
|
52
53
|
)
|
|
53
54
|
from ipor_fusion.crosschain.logs import log_address, log_bytes, log_topic0
|
|
54
55
|
from ipor_fusion.crosschain.messages import Command, CrosschainTransportKind
|
|
55
|
-
from ipor_fusion.types import
|
|
56
|
+
from ipor_fusion.types import (
|
|
57
|
+
Amount,
|
|
58
|
+
ChainId,
|
|
59
|
+
FuseAddress,
|
|
60
|
+
Period,
|
|
61
|
+
PositionSetHash,
|
|
62
|
+
ProposalId,
|
|
63
|
+
)
|
|
56
64
|
|
|
57
65
|
|
|
58
66
|
@dataclass(frozen=True, slots=True)
|
|
@@ -73,6 +81,7 @@ class LaneObservation:
|
|
|
73
81
|
# set pinned to the number the tag resolves to once keeps the tag's meaning.
|
|
74
82
|
# "pending" names no mined block and is left as is.
|
|
75
83
|
_MOVING_BLOCK_TAGS = frozenset({"latest", "safe", "finalized"})
|
|
84
|
+
_NO_MARGIN = Period(0)
|
|
76
85
|
|
|
77
86
|
|
|
78
87
|
@dataclass(frozen=True, slots=True)
|
|
@@ -86,8 +95,8 @@ class LaneHubState:
|
|
|
86
95
|
idle_ledger: Amount
|
|
87
96
|
dispatcher_ready: bool
|
|
88
97
|
chain_blocked: bool
|
|
89
|
-
last_approved_observed_at:
|
|
90
|
-
staleness_max:
|
|
98
|
+
last_approved_observed_at: Timestamp
|
|
99
|
+
staleness_max: Period
|
|
91
100
|
remote_state_version: int
|
|
92
101
|
has_active_command: bool
|
|
93
102
|
pending_transfer_count: int
|
|
@@ -233,7 +242,7 @@ class CrosschainLane(ABC):
|
|
|
233
242
|
def chain_blocked(self) -> Call[bool]:
|
|
234
243
|
return self.executor.chain_blocked(self.spoke_chain_id)
|
|
235
244
|
|
|
236
|
-
def last_approved_observed_at(self) -> Call[
|
|
245
|
+
def last_approved_observed_at(self) -> Call[Timestamp]:
|
|
237
246
|
"""Remote timestamp of the approved observation NAV freshness is
|
|
238
247
|
measured from; 0 before the first attestation."""
|
|
239
248
|
return self.executor.last_approved_observed_at(self.spoke_chain_id)
|
|
@@ -279,8 +288,8 @@ class CrosschainLane(ABC):
|
|
|
279
288
|
observation: LaneObservation,
|
|
280
289
|
*,
|
|
281
290
|
remote_block: int,
|
|
282
|
-
remote_timestamp:
|
|
283
|
-
expiry:
|
|
291
|
+
remote_timestamp: Timestamp,
|
|
292
|
+
expiry: Timestamp,
|
|
284
293
|
) -> BalanceObservation:
|
|
285
294
|
"""The proposal for ``observation``, read on the spoke at
|
|
286
295
|
``remote_block`` / ``remote_timestamp`` and valid on the hub until
|
|
@@ -297,7 +306,7 @@ class CrosschainLane(ABC):
|
|
|
297
306
|
tracked_position_set_hash=observation.tracked_position_set_hash,
|
|
298
307
|
)
|
|
299
308
|
|
|
300
|
-
def needs_attestation(self, *, now:
|
|
309
|
+
def needs_attestation(self, *, now: Timestamp, margin: Period = _NO_MARGIN) -> bool:
|
|
301
310
|
"""Whether a keeper should propose now (up to seven reads on the hub):
|
|
302
311
|
the settled bucket is non-zero, no transfer or command receipt is in
|
|
303
312
|
flight, and the approved observation is missing or older than
|
|
@@ -362,7 +371,7 @@ class CrosschainLane(ABC):
|
|
|
362
371
|
"""Bind ``min_received`` into the transport's send parameters."""
|
|
363
372
|
|
|
364
373
|
@abstractmethod
|
|
365
|
-
def staleness_max(self) -> Call[
|
|
374
|
+
def staleness_max(self) -> Call[Period]:
|
|
366
375
|
"""Seconds an approved observation keeps the settled bucket in NAV
|
|
367
376
|
(``STALENESS_MAX`` on Stargate, ``BALANCE_STALENESS_MAX`` on CCIP)."""
|
|
368
377
|
|
|
@@ -24,6 +24,7 @@ from ipor_fusion.types import (
|
|
|
24
24
|
CommandId,
|
|
25
25
|
DeploymentRequestId,
|
|
26
26
|
LayerZeroEid,
|
|
27
|
+
Period,
|
|
27
28
|
PlasmaVaultAddress,
|
|
28
29
|
PositionSetHash,
|
|
29
30
|
ProposalId,
|
|
@@ -111,8 +112,8 @@ class StargateCrosschainExecutor(CrosschainExecutor):
|
|
|
111
112
|
def local_chain_id(self) -> Call[ChainId]:
|
|
112
113
|
return self._view("LOCAL_CHAIN_ID()", output_types=["uint256"], decoder=ChainId)
|
|
113
114
|
|
|
114
|
-
def staleness_max(self) -> Call[
|
|
115
|
-
return self._view("STALENESS_MAX()", output_types=["uint256"])
|
|
115
|
+
def staleness_max(self) -> Call[Period]:
|
|
116
|
+
return self._view("STALENESS_MAX()", output_types=["uint256"], decoder=Period)
|
|
116
117
|
|
|
117
118
|
def deployment_ttl(self) -> Call[int]:
|
|
118
119
|
return self._view("DEPLOYMENT_TTL()", output_types=["uint256"])
|
{ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/lane.py
RENAMED
|
@@ -25,7 +25,7 @@ from ipor_fusion.crosschain.stargate.contracts import (
|
|
|
25
25
|
StargateCrosschainExecutor,
|
|
26
26
|
)
|
|
27
27
|
from ipor_fusion.crosschain.stargate.layerzero import OptionsBuilder
|
|
28
|
-
from ipor_fusion.types import Amount
|
|
28
|
+
from ipor_fusion.types import Amount, Period
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
class StargateLane(CrosschainLane):
|
|
@@ -73,7 +73,7 @@ class StargateLane(CrosschainLane):
|
|
|
73
73
|
fuses=fuses,
|
|
74
74
|
)
|
|
75
75
|
|
|
76
|
-
def staleness_max(self) -> Call[
|
|
76
|
+
def staleness_max(self) -> Call[Period]:
|
|
77
77
|
return self.executor.staleness_max()
|
|
78
78
|
|
|
79
79
|
def default_send(self, *, token: bool) -> StargateSendParams:
|
|
@@ -398,7 +398,7 @@ def vault_oracle_mapping(
|
|
|
398
398
|
|
|
399
399
|
resolve_access_manager(ctx, checksum)
|
|
400
400
|
|
|
401
|
-
mapping = build_oracle_mapping(ctx, checksum, effective_block)
|
|
401
|
+
mapping = build_oracle_mapping(ctx, checksum, effective_block=effective_block)
|
|
402
402
|
return OracleMappingResponse.from_mapping(mapping)
|
|
403
403
|
|
|
404
404
|
|
{ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/lending_health.py
RENAMED
|
@@ -94,7 +94,7 @@ class LendingMarketHealth:
|
|
|
94
94
|
"""Health status of a single lending market position.
|
|
95
95
|
|
|
96
96
|
`substrate_id` identifies the underlying market within the IPOR market_id:
|
|
97
|
-
- Morpho: the
|
|
97
|
+
- Morpho: the morpho market id (`0x` + 64 lowercase hex) (one row per substrate).
|
|
98
98
|
- Aave V3: None — Aave health is account-level, aggregated across reserves.
|
|
99
99
|
- Aave V4: the Spoke address — account-level per Spoke, across its reserves.
|
|
100
100
|
"""
|
{ipor_fusion-4.0.0.dev141 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/oracle_mapping.py
RENAMED
|
@@ -428,13 +428,14 @@ def _enumerate_assets(
|
|
|
428
428
|
def build_oracle_mapping(
|
|
429
429
|
ctx: Web3Context,
|
|
430
430
|
vault: PlasmaVaultAddress,
|
|
431
|
+
*,
|
|
431
432
|
effective_block: int,
|
|
432
433
|
max_depth: int = 6,
|
|
433
434
|
) -> OracleMapping:
|
|
434
435
|
"""Build the full oracle mapping for ``vault``.
|
|
435
436
|
|
|
436
|
-
``ctx`` must already be pinned to ``effective_block`` (
|
|
437
|
-
``ctx.
|
|
437
|
+
``ctx`` must already be pinned to ``effective_block`` (pass
|
|
438
|
+
``ctx.at_block(effective_block)``); the block is echoed in the output. Raises
|
|
438
439
|
`UnsupportedVaultVersionError` for a vault that exposes no price-oracle
|
|
439
440
|
getter.
|
|
440
441
|
"""
|