ipor-fusion 4.0.0.dev144__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.dev144 → ipor_fusion-4.0.0.dev146}/AGENTS.md +2 -1
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/MIGRATION_4.md +32 -16
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/PKG-INFO +1 -1
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +2 -2
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +2 -1
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_cmd.py +3 -1
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fusion_factory.py +9 -8
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/simulation.py +3 -3
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/contracts.py +5 -2
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/lane.py +2 -2
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/contracts.py +8 -4
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/lane.py +17 -8
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/contracts.py +3 -2
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/lane.py +2 -2
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/mcp/server.py +1 -1
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/lending_health.py +1 -1
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/oracle_mapping.py +1 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/validation.py +16 -16
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_data.py +14 -4
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_commands.py +9 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_oracle_mapping.py +4 -4
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_mcp_server.py +2 -2
- {ipor_fusion-4.0.0.dev144 → 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.dev144 → ipor_fusion-4.0.0.dev146}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/README.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_guide.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_public_api.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.0.0.dev144 → ipor_fusion-4.0.0.dev146}/tests/typed_client/rejected.py +0 -0
- {ipor_fusion-4.0.0.dev144 → 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
|
|
@@ -94,7 +94,7 @@ placeholder wrapper.
|
|
|
94
94
|
`aggregate3(calls)` still returns the raw `Call`), `VaultSimulator`,
|
|
95
95
|
`CrosschainSimulator` and `OracleMappingReader(ctx, oracle)`.
|
|
96
96
|
- Resolvers that probe the chain stay eager and return context-free wrappers:
|
|
97
|
-
`price_oracle_middleware(ctx,
|
|
97
|
+
`price_oracle_middleware(ctx, address)`, `resolve_access_manager(ctx, vault)`,
|
|
98
98
|
`ExternalStateExecutor.for_vault(ctx, vault)`. A resolved oracle carries the ABI
|
|
99
99
|
found on that chain and block; resolve again for another one.
|
|
100
100
|
- Crosschain lanes own both contexts: `CcipLane` / `StargateLane` take `hub_ctx=` and
|
|
@@ -113,9 +113,9 @@ placeholder wrapper.
|
|
|
113
113
|
do not see a CCIP recall or tell a parked command from a pending one. `CrosschainTransport.executor(address)`
|
|
114
114
|
and `.dispatcher(address)` no longer take a context.
|
|
115
115
|
- Chain-bound decoding takes the chain explicitly:
|
|
116
|
-
`ExternalStateExecutor.pending_proposals(
|
|
116
|
+
`ExternalStateExecutor.pending_proposals(balance_account, *, chain_id)`,
|
|
117
117
|
`parse_balance_proposed(log, *, chain_id)` and
|
|
118
|
-
`find_balance_proposed(logs,
|
|
118
|
+
`find_balance_proposed(logs, balance_account=None, *, chain_id)` require it (3.x fell back
|
|
119
119
|
to the wrapper's context). The decoder captures it, so `.call(ctx)`, `Multicall3`
|
|
120
120
|
and `VaultSimulator.observe` stamp the same hash for the same bytes, whatever
|
|
121
121
|
context executes them. Pass `ctx.chain_id` for the chain you read from.
|
|
@@ -134,7 +134,7 @@ placeholder wrapper.
|
|
|
134
134
|
| `call.build_transaction(block=b)`, `call.estimate_gas(block=b)` | `call.build_transaction(ctx, block=b)`, `call.estimate_gas(ctx, block=b)` |
|
|
135
135
|
| `call.ctx` | gone: keep the context yourself |
|
|
136
136
|
| `Multicall3(ctx, address)` | `Multicall3(ctx, address=address)` |
|
|
137
|
-
| `executor.pending_proposals(
|
|
137
|
+
| `executor.pending_proposals(balance_account)` | `executor.pending_proposals(balance_account, chain_id=ctx.chain_id)` |
|
|
138
138
|
| `executor.parse_balance_proposed(log)` / `find_balance_proposed(logs)` | `...(log, chain_id=...)` / `...(logs, chain_id=...)` |
|
|
139
139
|
| `CcipLane(executor=, dispatcher=, spoke_chain_id=, ...)` | `CcipLane(hub_ctx=, spoke_ctx=, executor=, dispatcher=, ...)` (same for `StargateLane`) |
|
|
140
140
|
| `transport.executor(ctx, address)` / `transport.dispatcher(ctx, address)` | `transport.executor(address)` / `transport.dispatcher(address)` |
|
|
@@ -174,7 +174,8 @@ The vault read is one pinned snapshot, and the chain is always the context's:
|
|
|
174
174
|
|
|
175
175
|
- `fetch_vault_data(ctx, vault, *, block=None, lending=True, metadata=True)` takes
|
|
176
176
|
the vault address (not a `PlasmaVault`) and no `chain_id`. It resolves one block
|
|
177
|
-
(`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
|
|
178
179
|
read, log scans included, on `ctx.at_block(block)`; `ctx` is not modified. In 3.x
|
|
179
180
|
`block_number` only selected the block reported in `VaultData`, and the reads ran
|
|
180
181
|
wherever `ctx` pointed. The old `chain_id=0` switch is `lending=False`;
|
|
@@ -289,6 +290,8 @@ fails at run time:
|
|
|
289
290
|
keyword.
|
|
290
291
|
- `encode_oft_compose_msg(*, nonce=, src_eid=, amount_ld=, compose_msg=)` takes
|
|
291
292
|
keyword arguments only.
|
|
293
|
+
- `build_oracle_mapping(ctx, vault, *, effective_block, max_depth=6)` takes
|
|
294
|
+
`effective_block` and `max_depth` by keyword.
|
|
292
295
|
- The vault parameter is named `vault` throughout: `validate_vault`,
|
|
293
296
|
`fetch_deployment_info`, `fetch_vault_lending_health`, `build_oracle_mapping`,
|
|
294
297
|
`read_external_state`, `ExternalStateExecutor.for_vault`, `read_hypercore_nav`,
|
|
@@ -434,8 +437,8 @@ are cached in a `ContractCache`, injected instead of always written to `~/.cache
|
|
|
434
437
|
explicitly (default: the file cache); pass `cache=ctx.cache` to share the
|
|
435
438
|
context's policy. The CLI's text and JSON output name contracts through the
|
|
436
439
|
context's cache.
|
|
437
|
-
- `build_vault_info_json(data)` without `resolve_name` names no contract (
|
|
438
|
-
`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
|
|
439
442
|
`resolve_name=partial(get_contract_name, chain_id, api_key=..., cache=ctx.cache)`
|
|
440
443
|
for the CLI's document.
|
|
441
444
|
- `ipor_fusion.cache` is a public module now and exports `ContractCache`,
|
|
@@ -536,13 +539,18 @@ converted amounts `Amount`. A custom `VaultState` annotates the same.
|
|
|
536
539
|
`PlasmaVault.total_supply()`, `balance_of()` and `get_total_supply_cap()` return
|
|
537
540
|
`Shares` (vault shares), and `transfer` / `approve` / `transfer_from` /
|
|
538
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`.
|
|
539
547
|
|
|
540
548
|
**Vault data and helpers.** `ensure_supported_chain` takes `ChainId`.
|
|
541
549
|
`fetch_unpriceable_priced_tokens` takes the oracle and underlying as
|
|
542
550
|
`ChecksumAddress`. `resolve_token_symbol`, `resolve_token_decimals`,
|
|
543
551
|
`get_contract_name` and `get_deployment_tx` take `HexAddress` (a checksum address
|
|
544
|
-
fits), and the `resolve_name`
|
|
545
|
-
|
|
552
|
+
fits), and the `resolve_name` callback receives one (a callback typed for `str`
|
|
553
|
+
still fits). Market-keyed data is keyed by `MarketId`:
|
|
546
554
|
`VaultData.market_substrates`, `dependency_graph`, `morpho_positions`,
|
|
547
555
|
`aave_positions`, `market_balances`; the `VaultState` protocol,
|
|
548
556
|
`fetch_vault_lending_health`, `fetch_unpriceable_priced_tokens` and the
|
|
@@ -566,8 +574,8 @@ The Uniswap V3 / Ramses V2 position events' `version`, `sender` and `recipient`
|
|
|
566
574
|
`MarketId`; `Erc20Holding.address` is `HexAddress`, and `SubstrateInfo.address` is
|
|
567
575
|
`HexAddress | None`. `LegacyPriceOracleMiddleware` takes `base_currency_decimals:
|
|
568
576
|
Decimals`, and `PriceOracleMiddleware.base_currency_decimals()` returns
|
|
569
|
-
`Call[Decimals]`. `get_logs_adaptive(chain_id=)`
|
|
570
|
-
`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
|
|
571
579
|
`OracleMappingReader.asset_source_events` take a `BlockIdentifier`.
|
|
572
580
|
|
|
573
581
|
**Address roles.** `PlasmaVault(address)`,
|
|
@@ -602,7 +610,8 @@ by `ChainId` (`HYPEREVM_CHAIN_ID` is one) and `explorer.SUPPORTED_CHAINS` is a
|
|
|
602
610
|
type-checks; `PUBLIC_ALLOCATOR_ADDRESSES` values are `ChecksumAddress`.
|
|
603
611
|
|
|
604
612
|
**Markets, substrates and access.** Every `IporFusionMarkets` member is a `MarketId`.
|
|
605
|
-
`
|
|
613
|
+
`market_name` and `format_market_label` take `MarketId`, `decode_substrate` a
|
|
614
|
+
`MarketId | None`.
|
|
606
615
|
`AccessManager.has_role`, `grant_role`, `revoke_role` and `read_accounts_with_role`
|
|
607
616
|
take `RoleId | Roles`; `RoleAccount.role_id` is `RoleId`.
|
|
608
617
|
|
|
@@ -630,7 +639,12 @@ on CCIP, `active_return` → `OperationId`, `asset_id`, `tracked_position_set_ha
|
|
|
630
639
|
`CcipObservation`, `OutboundMessage`, `CcipMessageSent`, `Any2EVMMessage`,
|
|
631
640
|
`VerifierResult`, `Packet.guid`, `TaxiMessage`, `StargateChain`; and the helpers
|
|
632
641
|
`fetch_verifier_result(message_id=)`, `lz_receive_calldata(guid=)` and
|
|
633
|
-
`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
|
|
634
648
|
(`ccip_events` → `CcipEvent.values`) stay a generic mapping: convert a value
|
|
635
649
|
before passing it on.
|
|
636
650
|
|
|
@@ -657,20 +671,22 @@ HyperCore ids; `HyperCorePerpAssetInfo`, `HyperCorePerpMarket`, `HyperCoreSpotLe
|
|
|
657
671
|
|
|
658
672
|
**External state.** `ExternalStateExecutor.proposal_hash` returns and `confirm_balance`
|
|
659
673
|
takes a `ProposalHash`; `BalanceProposal.proposal_hash` is a `ProposalHash`;
|
|
660
|
-
`ExternalStateEvent.transaction_hash` is a `TxHash`.
|
|
674
|
+
`ExternalStateEvent.transaction_hash` is a `TxHash | None`.
|
|
661
675
|
`ExternalStateVaultState.last_checked_custodian_timestamp`,
|
|
662
676
|
`BalanceFuseSnapshot.last_custodian_update_timestamp`, `BalanceProposal.proposed_at`,
|
|
663
677
|
`last_updated()` and `get_oldest_update_timestamp()` are web3's `Timestamp`, and
|
|
664
678
|
`ExternalStateExecutor.proposal_hash(proposed_at=)` takes one.
|
|
665
679
|
|
|
666
|
-
**Errors and explorer.** `TransactionError(tx_hash=)` takes a `TxHash`,
|
|
680
|
+
**Errors and explorer.** `TransactionError(tx_hash=)` takes a `TxHash | None`,
|
|
667
681
|
`LogScanError(address=)` a `ChecksumAddress`; `get_revert_reason` takes a `TxHash`;
|
|
668
682
|
`get_deployment_tx` returns a `TxHash` (a malformed hash from Etherscan is reported
|
|
669
683
|
as the error `malformed-tx-hash`).
|
|
670
684
|
|
|
671
685
|
**MCP response models** (Python constructors only; the JSON schemas are unchanged
|
|
672
686
|
except as listed under [Behavior changes](#behavior-changes)): `chain_id` fields are
|
|
673
|
-
`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
|
|
674
690
|
directly from Python takes `ChainId`.
|
|
675
691
|
|
|
676
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.dev144 → 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.dev144 → 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.dev144 → 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.dev144 → 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.dev144 → 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.dev144 → 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
|
"""
|
|
@@ -165,29 +165,29 @@ class Reconciliation:
|
|
|
165
165
|
only; ``erc20_direct_total`` is informational and never added to it.
|
|
166
166
|
"""
|
|
167
167
|
|
|
168
|
-
balance_fuses_total:
|
|
168
|
+
balance_fuses_total: Amount
|
|
169
169
|
balance_fuses_total_usd: float
|
|
170
|
-
underlying_on_vault:
|
|
170
|
+
underlying_on_vault: Amount
|
|
171
171
|
underlying_on_vault_usd: float
|
|
172
|
-
erc20_direct_total:
|
|
172
|
+
erc20_direct_total: Amount
|
|
173
173
|
erc20_direct_total_usd: float
|
|
174
|
-
sum:
|
|
174
|
+
sum: Amount
|
|
175
175
|
sum_usd: float
|
|
176
|
-
on_chain_total_assets:
|
|
176
|
+
on_chain_total_assets: Amount
|
|
177
177
|
on_chain_total_assets_usd: float | None
|
|
178
|
-
delta:
|
|
178
|
+
delta: Amount
|
|
179
179
|
delta_usd: float
|
|
180
180
|
delta_percent: float
|
|
181
181
|
# sharesToRelease of the WithdrawManager converted to assets.
|
|
182
|
-
pending_withdrawals:
|
|
182
|
+
pending_withdrawals: Amount
|
|
183
183
|
pending_withdrawals_usd: float
|
|
184
184
|
# totalAssets minus idle underlying: the global market total the vault
|
|
185
185
|
# stores, which per-market caches drift from after partial refreshes.
|
|
186
|
-
implied_market_total:
|
|
186
|
+
implied_market_total: Amount
|
|
187
187
|
|
|
188
188
|
@property
|
|
189
|
-
def market_storage_divergence(self) ->
|
|
190
|
-
return self.balance_fuses_total - self.implied_market_total
|
|
189
|
+
def market_storage_divergence(self) -> Amount:
|
|
190
|
+
return Amount(self.balance_fuses_total - self.implied_market_total)
|
|
191
191
|
|
|
192
192
|
|
|
193
193
|
@dataclass(frozen=True)
|
|
@@ -288,10 +288,10 @@ def _reconcile(state: VaultState) -> Reconciliation:
|
|
|
288
288
|
decimals = state.asset_decimals
|
|
289
289
|
price = state.asset_price_usd
|
|
290
290
|
|
|
291
|
-
balance_fuses_total = 0
|
|
291
|
+
balance_fuses_total = Amount(0)
|
|
292
292
|
balance_fuses_usd = 0.0
|
|
293
293
|
for balance in market_balances.values():
|
|
294
|
-
balance_fuses_total
|
|
294
|
+
balance_fuses_total = Amount(balance_fuses_total + balance)
|
|
295
295
|
if price is not None:
|
|
296
296
|
balance_fuses_usd += (balance / 10**decimals) * price
|
|
297
297
|
|
|
@@ -300,17 +300,17 @@ def _reconcile(state: VaultState) -> Reconciliation:
|
|
|
300
300
|
if underlying > 0 and price:
|
|
301
301
|
underlying_usd = (underlying / 10**decimals) * price
|
|
302
302
|
|
|
303
|
-
total = balance_fuses_total + underlying
|
|
303
|
+
total = Amount(balance_fuses_total + underlying)
|
|
304
304
|
total_usd = balance_fuses_usd + underlying_usd
|
|
305
305
|
on_chain = state.total_assets
|
|
306
|
-
delta = total - on_chain
|
|
306
|
+
delta = Amount(total - on_chain)
|
|
307
307
|
delta_usd = abs(total_usd - (on_chain / 10**decimals * price)) if price else 0
|
|
308
308
|
delta_percent = abs(delta / on_chain * 100) if on_chain else 0.0
|
|
309
309
|
|
|
310
310
|
# totalAssets reads the global market total while balance fuses report
|
|
311
311
|
# per-market caches; they diverge after withdrawals with sharesToRelease,
|
|
312
312
|
# which refresh only the markets the instant-withdrawal fuses touch.
|
|
313
|
-
pending = 0
|
|
313
|
+
pending = Amount(0)
|
|
314
314
|
pending_usd = 0.0
|
|
315
315
|
queue = state.withdraw_manager_data
|
|
316
316
|
if queue and queue.shares_to_release > 0:
|
|
@@ -336,7 +336,7 @@ def _reconcile(state: VaultState) -> Reconciliation:
|
|
|
336
336
|
delta_percent=delta_percent,
|
|
337
337
|
pending_withdrawals=pending,
|
|
338
338
|
pending_withdrawals_usd=pending_usd,
|
|
339
|
-
implied_market_total=max(0, on_chain - underlying),
|
|
339
|
+
implied_market_total=Amount(max(0, on_chain - underlying)),
|
|
340
340
|
)
|
|
341
341
|
|
|
342
342
|
|
|
@@ -532,6 +532,16 @@ def _fetch_lending_reads(
|
|
|
532
532
|
)
|
|
533
533
|
|
|
534
534
|
|
|
535
|
+
def _pinned_default_block(ctx: Web3Context) -> int | None:
|
|
536
|
+
"""The number ``ctx.default_block`` names, or None for the latest block."""
|
|
537
|
+
default = ctx.default_block
|
|
538
|
+
if isinstance(default, int):
|
|
539
|
+
return default
|
|
540
|
+
if default in ("latest", "pending"):
|
|
541
|
+
return None
|
|
542
|
+
return ctx.web3.eth.get_block(default)["number"]
|
|
543
|
+
|
|
544
|
+
|
|
535
545
|
def fetch_vault_data(
|
|
536
546
|
ctx: Web3Context,
|
|
537
547
|
vault: PlasmaVaultAddress,
|
|
@@ -541,8 +551,8 @@ def fetch_vault_data(
|
|
|
541
551
|
metadata: bool = True,
|
|
542
552
|
) -> VaultData:
|
|
543
553
|
"""Read the vault's state at one block: ``block``, else the context's
|
|
544
|
-
default block
|
|
545
|
-
up front. Every read, log scans included, runs on a copy of ``ctx`` pinned
|
|
554
|
+
default block (a ``safe`` / ``finalized`` tag or a block hash is resolved
|
|
555
|
+
to its number), else the latest block, resolved once up front. Every read, log scans included, runs on a copy of ``ctx`` pinned
|
|
546
556
|
to that block (`Web3Context.at_block`); ``ctx`` itself is not modified.
|
|
547
557
|
The chain is ``ctx.chain_id``.
|
|
548
558
|
|
|
@@ -561,8 +571,8 @@ def fetch_vault_data(
|
|
|
561
571
|
# Fail fast with a client-mappable typed error instead of letting the
|
|
562
572
|
# fetch die deep in the stack on chains the tooling is not validated on.
|
|
563
573
|
ensure_supported_chain(ctx.chain_id)
|
|
564
|
-
if block is None
|
|
565
|
-
block = ctx
|
|
574
|
+
if block is None:
|
|
575
|
+
block = _pinned_default_block(ctx)
|
|
566
576
|
resolved_block = ctx.web3.eth.block_number if block is None else block
|
|
567
577
|
is_latest = block is None
|
|
568
578
|
ctx = ctx.at_block(resolved_block)
|