ipor-fusion 4.2.0.dev9__tar.gz → 4.2.0.dev14__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.2.0.dev9 → ipor_fusion-4.2.0.dev14}/PKG-INFO +3 -3
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/README.md +2 -2
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/pyproject.toml +1 -1
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/__init__.py +10 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/vault_markets_view.py +3 -3
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/__init__.py +7 -1
- ipor_fusion-4.2.0.dev14/src/ipor_fusion/fuses/compound_v3.py +62 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/market_ids.py +4 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/__init__.py +9 -1
- ipor_fusion-4.2.0.dev14/src/ipor_fusion/readers/compound_v3.py +164 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/lending_health.py +132 -54
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/substrates.py +1 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/validation.py +8 -2
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/vault_data.py +8 -4
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/vault_positions.py +28 -1
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/constants.py +18 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_lending_health.py +202 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_vault_predates_getters.py +1 -1
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_fuse_encoding.py +37 -1
- ipor_fusion-4.2.0.dev14/tests/test_lending_health_compound_v3_onchain.py +87 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_public_api.py +10 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_reader_encoding.py +15 -1
- ipor_fusion-4.2.0.dev14/tests/test_simulate_compound_v3_institutional_usdc.py +453 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_solidity_mirrors.py +2 -3
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_validation.py +8 -0
- ipor_fusion-4.2.0.dev9/src/ipor_fusion/fuses/compound_v3.py +0 -23
- ipor_fusion-4.2.0.dev9/src/ipor_fusion/readers/compound_v3.py +0 -21
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.env.example +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.gemini/settings.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.gitignore +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/.python-version +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/AGENTS.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/CHANGELOG.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/CLAUDE.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/CODEOWNERS +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/LICENSE +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/MIGRATION_4.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/build.sh +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/examples/README.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/examples/hypercore_vault_official_deployment_hyperevm.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/pytest.ini +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/scripts/fusion_error_signatures.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/skills/ipor-deploy-vault/SKILL.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/address_cmd.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/fuse_cmd.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/preflight_cmd.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/context_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/fuse_decoding.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/fusion_factory.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/simulation_result.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuse_whitelist.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/hypercore_pre_hooks.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/fusion_errors.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/guide/quickstart.md +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/hypercore/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/mcp/server.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/onchain_text.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/preflight.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/euler_v2.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/registry.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/types.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_addresses.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_event_args.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_fake_rpc.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_foundry.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_golden.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_guide.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_live.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_multicall.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_oracle_mapping_fake.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_simulate.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/_validation.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/addresses.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/conftest.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/hypercore_official.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_blue.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/simulate_v1_request.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/fetched.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/full.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/full.txt +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_about.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_addresses_helper.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cache.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_ccip_read_disabled.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_chains.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_address.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_market_golden.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_mcp_fuse_whitelist.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_mcp_parity.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_oracle_mapping_golden.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_preflight.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_examples_hypercore_hyperevm.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_fuse_decoding.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_fuse_whitelist.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_fusion_errors.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_governance_wrappers.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_guide.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_hypercore_pre_hooks.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_logs.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_mcp_address.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_mcp_preflight.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_onchain_text.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_preflight.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_registry.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_roles.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_examples_hyperevm.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_preflight_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_timelock_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulation_errors.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_simulation_observation.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_types_and_events.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_vault_data_block.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_vault_info_fetched_golden.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_vault_reconciliation_onchain_base.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/tests/typed_client/rejected.py +0 -0
- {ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ipor-fusion
|
|
3
|
-
Version: 4.2.0.
|
|
3
|
+
Version: 4.2.0.dev14
|
|
4
4
|
Summary: The IPOR Fusion SDK for Python
|
|
5
5
|
Project-URL: homepage, https://ipor.io
|
|
6
6
|
Project-URL: repository, https://github.com/IPOR-Labs/ipor-fusion.py
|
|
@@ -520,7 +520,7 @@ Fuse.method() --> FuseAction --> PlasmaVault.execute([actions]) --> Call
|
|
|
520
520
|
| Euler V2 | `EulerV2SupplyFuse`, `EulerV2CollateralFuse`, `EulerV2ControllerFuse`, `EulerV2BorrowFuse`, `EulerV2BatchFuse`, `EulerV2SwapDeployFuse`, `EulerV2SwapReconfigureFuse`, `EulerV2SwapRegistryFuse` |
|
|
521
521
|
| Uniswap V3 | `UniswapV3SwapFuse`, `UniswapV3NewPositionFuse`, `UniswapV3ModifyPositionFuse`, `UniswapV3CollectFuse` |
|
|
522
522
|
| Ramses V2 | `RamsesV2NewPositionFuse`, `RamsesV2ModifyPositionFuse`, `RamsesV2CollectFuse`, `RamsesClaimFuse` |
|
|
523
|
-
| Compound V3 | `CompoundV3SupplyFuse` |
|
|
523
|
+
| Compound V3 | `CompoundV3SupplyFuse`, `CompoundV3BorrowFuse`, `CompoundV3ClaimFuse` |
|
|
524
524
|
| Gearbox V3 | `GearboxSupplyFuse`, `GearboxStakeFuse` |
|
|
525
525
|
| ERC-4626 | `ERC4626SupplyFuse` |
|
|
526
526
|
| Fluid Instadapp | `FluidInstadappSupplyFuse`, `FluidInstadappStakingFuse` |
|
|
@@ -564,7 +564,7 @@ Read-only aggregators over positions and health, no fuses involved:
|
|
|
564
564
|
|--------|---------|
|
|
565
565
|
| `MorphoReader`, `AaveV3Reader`, `CompoundV3Reader` | Market params, rates and vault positions per lending protocol |
|
|
566
566
|
| `UniswapV3Reader`, `RamsesV2Reader` | LP position details |
|
|
567
|
-
| `fetch_vault_lending_health` | Health factor per lending market a vault is in (Morpho, Aave V3/V4, Euler V2; any other market that can borrow is listed as unreadable) |
|
|
567
|
+
| `fetch_vault_lending_health` | Health factor per lending market a vault is in (Morpho, Aave V3/V4, Euler V2, Compound V3; any other market that can borrow is listed as unreadable) |
|
|
568
568
|
| `build_oracle_mapping` | How the vault prices every configured asset |
|
|
569
569
|
|
|
570
570
|
### Supported networks
|
|
@@ -471,7 +471,7 @@ Fuse.method() --> FuseAction --> PlasmaVault.execute([actions]) --> Call
|
|
|
471
471
|
| Euler V2 | `EulerV2SupplyFuse`, `EulerV2CollateralFuse`, `EulerV2ControllerFuse`, `EulerV2BorrowFuse`, `EulerV2BatchFuse`, `EulerV2SwapDeployFuse`, `EulerV2SwapReconfigureFuse`, `EulerV2SwapRegistryFuse` |
|
|
472
472
|
| Uniswap V3 | `UniswapV3SwapFuse`, `UniswapV3NewPositionFuse`, `UniswapV3ModifyPositionFuse`, `UniswapV3CollectFuse` |
|
|
473
473
|
| Ramses V2 | `RamsesV2NewPositionFuse`, `RamsesV2ModifyPositionFuse`, `RamsesV2CollectFuse`, `RamsesClaimFuse` |
|
|
474
|
-
| Compound V3 | `CompoundV3SupplyFuse` |
|
|
474
|
+
| Compound V3 | `CompoundV3SupplyFuse`, `CompoundV3BorrowFuse`, `CompoundV3ClaimFuse` |
|
|
475
475
|
| Gearbox V3 | `GearboxSupplyFuse`, `GearboxStakeFuse` |
|
|
476
476
|
| ERC-4626 | `ERC4626SupplyFuse` |
|
|
477
477
|
| Fluid Instadapp | `FluidInstadappSupplyFuse`, `FluidInstadappStakingFuse` |
|
|
@@ -515,7 +515,7 @@ Read-only aggregators over positions and health, no fuses involved:
|
|
|
515
515
|
|--------|---------|
|
|
516
516
|
| `MorphoReader`, `AaveV3Reader`, `CompoundV3Reader` | Market params, rates and vault positions per lending protocol |
|
|
517
517
|
| `UniswapV3Reader`, `RamsesV2Reader` | LP position details |
|
|
518
|
-
| `fetch_vault_lending_health` | Health factor per lending market a vault is in (Morpho, Aave V3/V4, Euler V2; any other market that can borrow is listed as unreadable) |
|
|
518
|
+
| `fetch_vault_lending_health` | Health factor per lending market a vault is in (Morpho, Aave V3/V4, Euler V2, Compound V3; any other market that can borrow is listed as unreadable) |
|
|
519
519
|
| `build_oracle_mapping` | How the vault prices every configured asset |
|
|
520
520
|
|
|
521
521
|
### Supported networks
|
|
@@ -171,6 +171,8 @@ from ipor_fusion.fuses import (
|
|
|
171
171
|
AaveV3SupplyFuse,
|
|
172
172
|
AsyncActionFuse,
|
|
173
173
|
AsyncActionSubstrates,
|
|
174
|
+
CompoundV3BorrowFuse,
|
|
175
|
+
CompoundV3ClaimFuse,
|
|
174
176
|
CompoundV3SupplyFuse,
|
|
175
177
|
ERC4626SupplyFuse,
|
|
176
178
|
EulerSwapDynamicParams,
|
|
@@ -310,6 +312,9 @@ from ipor_fusion.readers import (
|
|
|
310
312
|
AaveV4OracleReader,
|
|
311
313
|
AaveV4SpokeReader,
|
|
312
314
|
AaveV4UserAccountData,
|
|
315
|
+
CometAccountValue,
|
|
316
|
+
CometAssetInfo,
|
|
317
|
+
CompoundV3FuseReader,
|
|
313
318
|
CompoundV3Reader,
|
|
314
319
|
LendingMarketHealth,
|
|
315
320
|
MiddlewarePricedToken,
|
|
@@ -656,6 +661,8 @@ __all__ = [
|
|
|
656
661
|
"UniswapV3NewPositionEvent",
|
|
657
662
|
"UniswapV3ClosePositionEvent",
|
|
658
663
|
"UniswapV3Events",
|
|
664
|
+
"CompoundV3BorrowFuse",
|
|
665
|
+
"CompoundV3ClaimFuse",
|
|
659
666
|
"CompoundV3SupplyFuse",
|
|
660
667
|
"RamsesV2NewPositionFuse",
|
|
661
668
|
"RamsesV2ModifyPositionFuse",
|
|
@@ -784,6 +791,9 @@ __all__ = [
|
|
|
784
791
|
"AaveV4OracleReader",
|
|
785
792
|
"AaveV4SpokeReader",
|
|
786
793
|
"AaveV4UserAccountData",
|
|
794
|
+
"CometAccountValue",
|
|
795
|
+
"CometAssetInfo",
|
|
796
|
+
"CompoundV3FuseReader",
|
|
787
797
|
"CompoundV3Reader",
|
|
788
798
|
"HYPEREVM_CHAIN_ID",
|
|
789
799
|
"LendingMarketHealth",
|
{ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/cli/vault_markets_view.py
RENAMED
|
@@ -116,8 +116,8 @@ def _index_lending_health(
|
|
|
116
116
|
"""Split lending health rows by protocol for fast lookup during rendering.
|
|
117
117
|
|
|
118
118
|
Morpho rows are keyed by morpho substrate id (one row per substrate).
|
|
119
|
-
Aave V3 rows are keyed by IPOR market id (account-aggregated,
|
|
120
|
-
market); Aave V4 rows by Spoke address (account-aggregated per Spoke) and
|
|
119
|
+
Aave V3 and Compound V3 rows are keyed by IPOR market id (account-aggregated,
|
|
120
|
+
one row per market); Aave V4 rows by Spoke address (account-aggregated per Spoke) and
|
|
121
121
|
Euler V2 rows by sub-account address, in the same account-level map.
|
|
122
122
|
"""
|
|
123
123
|
morpho: dict[str, LendingMarketHealth] = {}
|
|
@@ -127,7 +127,7 @@ def _index_lending_health(
|
|
|
127
127
|
for m in lh.markets:
|
|
128
128
|
if m.protocol == "morpho" and m.substrate_id:
|
|
129
129
|
morpho[str(m.substrate_id).lower().removeprefix("0x")] = m
|
|
130
|
-
elif m.protocol
|
|
130
|
+
elif m.protocol in ("aave_v3", "compound_v3"):
|
|
131
131
|
aave[m.market_id] = m
|
|
132
132
|
elif m.protocol in ("aave_v4", "euler_v2") and m.substrate_id:
|
|
133
133
|
aave[m.substrate_id] = m
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
from ipor_fusion.fuses.aave_v3 import AaveV3BorrowFuse, AaveV3SupplyFuse
|
|
2
2
|
from ipor_fusion.fuses.async_action import AsyncActionFuse, AsyncActionSubstrates
|
|
3
3
|
from ipor_fusion.fuses.base import Fuse, FuseAction, StakeFuse
|
|
4
|
-
from ipor_fusion.fuses.compound_v3 import
|
|
4
|
+
from ipor_fusion.fuses.compound_v3 import (
|
|
5
|
+
CompoundV3BorrowFuse,
|
|
6
|
+
CompoundV3ClaimFuse,
|
|
7
|
+
CompoundV3SupplyFuse,
|
|
8
|
+
)
|
|
5
9
|
from ipor_fusion.fuses.erc4626 import ERC4626SupplyFuse
|
|
6
10
|
from ipor_fusion.fuses.euler_v2 import (
|
|
7
11
|
EulerSwapDynamicParams,
|
|
@@ -112,6 +116,8 @@ __all__ = [
|
|
|
112
116
|
"UniswapV3NewPositionEvent",
|
|
113
117
|
"UniswapV3ClosePositionEvent",
|
|
114
118
|
"UniswapV3Events",
|
|
119
|
+
"CompoundV3BorrowFuse",
|
|
120
|
+
"CompoundV3ClaimFuse",
|
|
115
121
|
"CompoundV3SupplyFuse",
|
|
116
122
|
"RamsesV2NewPositionFuse",
|
|
117
123
|
"RamsesV2ModifyPositionFuse",
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from eth_typing import ChecksumAddress
|
|
2
|
+
|
|
3
|
+
from ipor_fusion.fuses.base import Fuse, FuseAction
|
|
4
|
+
from ipor_fusion.types import Amount
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CompoundV3SupplyFuse(Fuse):
|
|
8
|
+
"""Fuse for supplying and withdrawing assets on Compound V3."""
|
|
9
|
+
|
|
10
|
+
SIGNATURES = (
|
|
11
|
+
"enter((address,uint256))",
|
|
12
|
+
"exit((address,uint256))",
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
def supply(self, *, asset: ChecksumAddress, amount: Amount) -> FuseAction:
|
|
16
|
+
self._validate_address(asset, "asset")
|
|
17
|
+
self._validate_amount(amount, "amount")
|
|
18
|
+
return self._action_raw("enter((address,uint256))", [[asset, amount]])
|
|
19
|
+
|
|
20
|
+
def withdraw(self, *, asset: ChecksumAddress, amount: Amount) -> FuseAction:
|
|
21
|
+
self._validate_address(asset, "asset")
|
|
22
|
+
self._validate_amount(amount, "amount")
|
|
23
|
+
return self._action_raw("exit((address,uint256))", [[asset, amount]])
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class CompoundV3BorrowFuse(Fuse):
|
|
27
|
+
"""Fuse for borrowing and repaying the base token of a Comet.
|
|
28
|
+
|
|
29
|
+
The fuse is bound to one Comet, whose base token is the only asset it can
|
|
30
|
+
borrow, so neither action names an asset; the base token must be granted as
|
|
31
|
+
a substrate of the fuse's market. A repay is capped at the debt, so
|
|
32
|
+
``MAX_UINT256`` repays in full.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
SIGNATURES = (
|
|
36
|
+
"enter((uint256))",
|
|
37
|
+
"exit((uint256))",
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def borrow(self, *, amount: Amount) -> FuseAction:
|
|
41
|
+
self._validate_amount(amount, "amount")
|
|
42
|
+
return self._action_raw("enter((uint256))", [[amount]])
|
|
43
|
+
|
|
44
|
+
def repay(self, *, amount: Amount) -> FuseAction:
|
|
45
|
+
self._validate_amount(amount, "amount")
|
|
46
|
+
return self._action_raw("exit((uint256))", [[amount]])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class CompoundV3ClaimFuse(Fuse):
|
|
50
|
+
"""Fuse for claiming a Comet's rewards to the vault's rewards claim manager.
|
|
51
|
+
|
|
52
|
+
The fuse is bound to one ``CometRewards``. Route the action through
|
|
53
|
+
``RewardsManager.claim_rewards(...)``, not ``PlasmaVault.execute(...)``, and
|
|
54
|
+
register the fuse with ``RewardsManager.add_reward_fuses(...)`` first. A
|
|
55
|
+
Comet with no reward token configured reverts ``NotSupported(address)``.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
SIGNATURES = ("claim(address)",)
|
|
59
|
+
|
|
60
|
+
def claim(self, *, comet: ChecksumAddress) -> FuseAction:
|
|
61
|
+
self._validate_address(comet, "comet")
|
|
62
|
+
return self._action_raw("claim(address)", [comet])
|
|
@@ -106,6 +106,10 @@ class IporFusionMarkets:
|
|
|
106
106
|
# Substrate type: HyperCoreSubstrateLib (1 SpotToken, 2 PerpMarket,
|
|
107
107
|
# 3 Destination, 4 Builder, 5 Config, 6 SendCap, 7 PerpPositionCap).
|
|
108
108
|
HYPERCORE = MarketId(55)
|
|
109
|
+
# Compound V3 Institutional USDC (ciUSDCv3) on Ethereum: its own Comet, so
|
|
110
|
+
# the Compound V3 fuses are deployed again under this id; substrates: asset
|
|
111
|
+
# addresses, as for COMPOUND_V3_USDC
|
|
112
|
+
COMPOUND_V3_INSTITUTIONAL_USDC = MarketId(57)
|
|
109
113
|
# POL unstaking via sPOLController. The out-of-band id is baked into the
|
|
110
114
|
# deployed fuses as an immutable (424243 = 0x67933), so it must match the
|
|
111
115
|
# deployments. Substrates per IporFusionMarkets.sol: the sPOLController
|
|
@@ -11,7 +11,12 @@ from ipor_fusion.readers.aave_v4 import (
|
|
|
11
11
|
AaveV4SpokeReader,
|
|
12
12
|
AaveV4UserAccountData,
|
|
13
13
|
)
|
|
14
|
-
from ipor_fusion.readers.compound_v3 import
|
|
14
|
+
from ipor_fusion.readers.compound_v3 import (
|
|
15
|
+
CometAccountValue,
|
|
16
|
+
CometAssetInfo,
|
|
17
|
+
CompoundV3FuseReader,
|
|
18
|
+
CompoundV3Reader,
|
|
19
|
+
)
|
|
15
20
|
from ipor_fusion.readers.hypercore import (
|
|
16
21
|
HYPEREVM_CHAIN_ID,
|
|
17
22
|
)
|
|
@@ -79,6 +84,9 @@ __all__ = [
|
|
|
79
84
|
"AaveV4OracleReader",
|
|
80
85
|
"AaveV4SpokeReader",
|
|
81
86
|
"AaveV4UserAccountData",
|
|
87
|
+
"CometAccountValue",
|
|
88
|
+
"CometAssetInfo",
|
|
89
|
+
"CompoundV3FuseReader",
|
|
82
90
|
"CompoundV3Reader",
|
|
83
91
|
"HYPEREVM_CHAIN_ID",
|
|
84
92
|
"LendingMarketHealth",
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
from eth_typing import ChecksumAddress
|
|
4
|
+
from web3 import Web3
|
|
5
|
+
|
|
6
|
+
from ipor_fusion.core.context import Web3Context
|
|
7
|
+
from ipor_fusion.core.contract import Call, ContractWrapper
|
|
8
|
+
from ipor_fusion.core.multicall import Multicall3
|
|
9
|
+
from ipor_fusion.types import Amount
|
|
10
|
+
|
|
11
|
+
COMET_FACTOR_SCALE = 10**18
|
|
12
|
+
COMET_PRICE_SCALE = 10**8
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True, slots=True)
|
|
16
|
+
class CometAssetInfo:
|
|
17
|
+
"""A collateral listing of a Comet; the factors are scaled by 1e18."""
|
|
18
|
+
|
|
19
|
+
asset: ChecksumAddress
|
|
20
|
+
price_feed: ChecksumAddress
|
|
21
|
+
scale: int
|
|
22
|
+
borrow_collateral_factor: int
|
|
23
|
+
liquidate_collateral_factor: int
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(frozen=True, slots=True)
|
|
27
|
+
class CometAccountValue:
|
|
28
|
+
"""An account's position in the Comet's own prices, scaled by 1e8.
|
|
29
|
+
|
|
30
|
+
The unit is the Comet's price unit: USD on USD-priced Comets, ETH on a WETH
|
|
31
|
+
Comet. ``liquidation_limit`` is the collateral at its liquidation factors;
|
|
32
|
+
the account is liquidatable when ``debt`` exceeds it.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
collateral: int
|
|
36
|
+
liquidation_limit: int
|
|
37
|
+
debt: int
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _asset_info_decoder(
|
|
41
|
+
value: tuple[int, str, str, int, int, int, int, int],
|
|
42
|
+
) -> CometAssetInfo:
|
|
43
|
+
_, asset, price_feed, scale, borrow_factor, liquidate_factor, _, _ = value
|
|
44
|
+
return CometAssetInfo(
|
|
45
|
+
asset=Web3.to_checksum_address(asset),
|
|
46
|
+
price_feed=Web3.to_checksum_address(price_feed),
|
|
47
|
+
scale=scale,
|
|
48
|
+
borrow_collateral_factor=borrow_factor,
|
|
49
|
+
liquidate_collateral_factor=liquidate_factor,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class CompoundV3FuseReader(ContractWrapper):
|
|
54
|
+
"""Reader for the immutables of an IPOR Fusion Compound V3 fuse.
|
|
55
|
+
|
|
56
|
+
A Fusion market is bound to one Comet per chain through its fuses, so the
|
|
57
|
+
Comet behind a market is a property of its fuse.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def comet(self) -> Call[ChecksumAddress]:
|
|
61
|
+
return self._view(
|
|
62
|
+
"COMET()", output_types=["address"], decoder=Web3.to_checksum_address
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class CompoundV3Reader(ContractWrapper):
|
|
67
|
+
"""Reader for Compound V3 (Comet) on-chain state."""
|
|
68
|
+
|
|
69
|
+
def balance_of(self, account: ChecksumAddress) -> Call[Amount]:
|
|
70
|
+
return self._view(
|
|
71
|
+
"balanceOf(address)", account, output_types=["uint256"], decoder=Amount
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
def borrow_balance_of(self, account: ChecksumAddress) -> Call[Amount]:
|
|
75
|
+
return self._view(
|
|
76
|
+
"borrowBalanceOf(address)",
|
|
77
|
+
account,
|
|
78
|
+
output_types=["uint256"],
|
|
79
|
+
decoder=Amount,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
def collateral_balance_of(
|
|
83
|
+
self, account: ChecksumAddress, asset: ChecksumAddress
|
|
84
|
+
) -> Call[Amount]:
|
|
85
|
+
return self._view(
|
|
86
|
+
"collateralBalanceOf(address,address)",
|
|
87
|
+
account,
|
|
88
|
+
asset,
|
|
89
|
+
output_types=["uint128"],
|
|
90
|
+
decoder=Amount,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
def base_scale(self) -> Call[int]:
|
|
94
|
+
return self._view("baseScale()", output_types=["uint256"])
|
|
95
|
+
|
|
96
|
+
def base_token_price_feed(self) -> Call[ChecksumAddress]:
|
|
97
|
+
return self._view(
|
|
98
|
+
"baseTokenPriceFeed()",
|
|
99
|
+
output_types=["address"],
|
|
100
|
+
decoder=Web3.to_checksum_address,
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
def get_price(self, price_feed: ChecksumAddress) -> Call[int]:
|
|
104
|
+
return self._view("getPrice(address)", price_feed, output_types=["uint256"])
|
|
105
|
+
|
|
106
|
+
def num_assets(self) -> Call[int]:
|
|
107
|
+
return self._view("numAssets()", output_types=["uint8"])
|
|
108
|
+
|
|
109
|
+
def get_asset_info(self, index: int) -> Call[CometAssetInfo]:
|
|
110
|
+
return self._view(
|
|
111
|
+
"getAssetInfo(uint8)",
|
|
112
|
+
index,
|
|
113
|
+
output_types=[
|
|
114
|
+
"(uint8,address,address,uint64,uint64,uint64,uint64,uint128)"
|
|
115
|
+
],
|
|
116
|
+
decoder=_asset_info_decoder,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def read_account_value(
|
|
120
|
+
self, ctx: Web3Context, account: ChecksumAddress
|
|
121
|
+
) -> CometAccountValue:
|
|
122
|
+
"""Value ``account``'s collateral and debt as the Comet does, over every
|
|
123
|
+
collateral it lists rather than the vault's substrates: a revoked substrate
|
|
124
|
+
does not take collateral out of the account. Only the feeds of held assets
|
|
125
|
+
are read, as `isLiquidatable` does, so a broken feed of an asset the account
|
|
126
|
+
does not hold cannot hide its position (four batches)."""
|
|
127
|
+
multicall = Multicall3(ctx)
|
|
128
|
+
batch = multicall.batch()
|
|
129
|
+
count = batch.add(self.num_assets())
|
|
130
|
+
base_scale = batch.add(self.base_scale())
|
|
131
|
+
base_feed = batch.add(self.base_token_price_feed())
|
|
132
|
+
debt = batch.add(self.borrow_balance_of(account))
|
|
133
|
+
batch.run()
|
|
134
|
+
|
|
135
|
+
infos = multicall.aggregate(
|
|
136
|
+
[self.get_asset_info(i) for i in range(count.value)]
|
|
137
|
+
)
|
|
138
|
+
balances = multicall.aggregate(
|
|
139
|
+
[self.collateral_balance_of(account, info.asset) for info in infos]
|
|
140
|
+
)
|
|
141
|
+
held = [
|
|
142
|
+
(info, balance)
|
|
143
|
+
for info, balance in zip(infos, balances, strict=True)
|
|
144
|
+
if balance > 0
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
batch = multicall.batch()
|
|
148
|
+
base_price = batch.add(self.get_price(base_feed.value))
|
|
149
|
+
prices = [batch.add(self.get_price(info.price_feed)) for info, _ in held]
|
|
150
|
+
batch.run()
|
|
151
|
+
|
|
152
|
+
collateral = 0
|
|
153
|
+
liquidation_limit = 0
|
|
154
|
+
for (info, balance), price in zip(held, prices, strict=True):
|
|
155
|
+
value = balance * price.value // info.scale
|
|
156
|
+
collateral += value
|
|
157
|
+
liquidation_limit += (
|
|
158
|
+
value * info.liquidate_collateral_factor // COMET_FACTOR_SCALE
|
|
159
|
+
)
|
|
160
|
+
return CometAccountValue(
|
|
161
|
+
collateral=collateral,
|
|
162
|
+
liquidation_limit=liquidation_limit,
|
|
163
|
+
debt=debt.value * base_price.value // base_scale.value,
|
|
164
|
+
)
|
{ipor_fusion-4.2.0.dev9 → ipor_fusion-4.2.0.dev14}/src/ipor_fusion/readers/lending_health.py
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
"""Lending health computation for Morpho Blue, Aave V3, Aave V4
|
|
1
|
+
"""Lending health computation for Morpho Blue, Aave V3, Aave V4, Euler V2 and
|
|
2
|
+
Compound V3 markets.
|
|
2
3
|
|
|
3
4
|
Provides a unified view of LTV, liquidation thresholds, and health factors
|
|
4
5
|
for lending positions held by Plasma Vaults.
|
|
@@ -7,8 +8,10 @@ for lending positions held by Plasma Vaults.
|
|
|
7
8
|
from __future__ import annotations
|
|
8
9
|
|
|
9
10
|
import logging
|
|
11
|
+
from collections.abc import Callable
|
|
10
12
|
from concurrent.futures import ThreadPoolExecutor
|
|
11
13
|
from dataclasses import dataclass, field
|
|
14
|
+
from functools import partial
|
|
12
15
|
|
|
13
16
|
import requests
|
|
14
17
|
from eth_abi import decode
|
|
@@ -30,6 +33,7 @@ from ipor_fusion.errors import EmptyCallResultError
|
|
|
30
33
|
from ipor_fusion.market_ids import IporFusionMarkets
|
|
31
34
|
from ipor_fusion.readers.aave_v3 import AaveV3Reader
|
|
32
35
|
from ipor_fusion.readers.aave_v4 import AaveV4OracleReader, AaveV4SpokeReader
|
|
36
|
+
from ipor_fusion.readers.compound_v3 import COMET_PRICE_SCALE, CompoundV3Reader
|
|
33
37
|
from ipor_fusion.readers.euler_v2 import (
|
|
34
38
|
EULER_USD_UNIT_OF_ACCOUNT,
|
|
35
39
|
EulerV2Substrate,
|
|
@@ -123,6 +127,18 @@ EULER_V2_MARKET_IDS = frozenset(
|
|
|
123
127
|
}
|
|
124
128
|
)
|
|
125
129
|
|
|
130
|
+
# Market IDs served by the Compound V3 fuses. One Comet per market, read from its
|
|
131
|
+
# balance fuse. Health is account-level; a Comet account owing nothing has no
|
|
132
|
+
# liquidation risk and no row. The WETH Comet prices in ETH, not USD.
|
|
133
|
+
COMPOUND_V3_MARKET_IDS = frozenset(
|
|
134
|
+
{
|
|
135
|
+
IporFusionMarkets.COMPOUND_V3_USDC,
|
|
136
|
+
IporFusionMarkets.COMPOUND_V3_USDT,
|
|
137
|
+
IporFusionMarkets.COMPOUND_V3_WETH,
|
|
138
|
+
IporFusionMarkets.COMPOUND_V3_INSTITUTIONAL_USDC,
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
|
|
126
142
|
# Markets whose fuses can borrow but whose health has no reader yet. Their
|
|
127
143
|
# positions are listed as unreadable rather than left out: an unknown
|
|
128
144
|
# liquidation risk is not a healthy one. Dolomite counts only when a
|
|
@@ -146,6 +162,7 @@ class LendingMarketHealth:
|
|
|
146
162
|
- Aave V3: None — Aave health is account-level, aggregated across reserves.
|
|
147
163
|
- Aave V4: the Spoke address — account-level per Spoke, across its reserves.
|
|
148
164
|
- Euler V2: the sub-account address — account-level, across its collaterals.
|
|
165
|
+
- Compound V3: None — account-level on the market's Comet, across its collaterals.
|
|
149
166
|
"""
|
|
150
167
|
|
|
151
168
|
protocol: str
|
|
@@ -437,6 +454,57 @@ def _compute_aave_v4_market_health(
|
|
|
437
454
|
)
|
|
438
455
|
|
|
439
456
|
|
|
457
|
+
def _compute_compound_v3_market_health(
|
|
458
|
+
ctx: Web3Context,
|
|
459
|
+
comet: ChecksumAddress,
|
|
460
|
+
vault_address: PlasmaVaultAddress,
|
|
461
|
+
ipor_market_id: MarketId,
|
|
462
|
+
market_name: str,
|
|
463
|
+
) -> LendingMarketHealth | UnreadableLendingMarket | None:
|
|
464
|
+
"""Compute LTV health for the vault's account on one Comet; None when it owes
|
|
465
|
+
nothing. The health factor is the liquidation limit over the debt, so it falls
|
|
466
|
+
to 1 where `Comet.isLiquidatable` turns true."""
|
|
467
|
+
try:
|
|
468
|
+
reader = CompoundV3Reader(comet)
|
|
469
|
+
if reader.borrow_balance_of(vault_address).call(ctx) == 0:
|
|
470
|
+
return None
|
|
471
|
+
account = reader.read_account_value(ctx, vault_address)
|
|
472
|
+
except _READ_ERRORS as exc:
|
|
473
|
+
return UnreadableLendingMarket(
|
|
474
|
+
protocol="compound_v3",
|
|
475
|
+
market_id=ipor_market_id,
|
|
476
|
+
market_name=market_name,
|
|
477
|
+
reason=_reason("account value", exc),
|
|
478
|
+
)
|
|
479
|
+
# Dust that prices to nothing: the Comet rounds it the same way and cannot
|
|
480
|
+
# liquidate it.
|
|
481
|
+
if account.debt == 0:
|
|
482
|
+
return None
|
|
483
|
+
|
|
484
|
+
has_collateral = account.collateral > 0
|
|
485
|
+
has_limit = account.liquidation_limit > 0
|
|
486
|
+
current_ltv = account.debt / account.collateral if has_collateral else None
|
|
487
|
+
max_ltv = account.liquidation_limit / account.collateral if has_collateral else 0.0
|
|
488
|
+
# With no limit the health factor is 0, a known liquidation risk; only the usage
|
|
489
|
+
# has no value.
|
|
490
|
+
ltv_usage = account.debt / account.liquidation_limit * 100 if has_limit else None
|
|
491
|
+
in_usd = ipor_market_id != IporFusionMarkets.COMPOUND_V3_WETH
|
|
492
|
+
|
|
493
|
+
return LendingMarketHealth(
|
|
494
|
+
protocol="compound_v3",
|
|
495
|
+
market_id=ipor_market_id,
|
|
496
|
+
market_name=market_name,
|
|
497
|
+
current_ltv=round(current_ltv, 6) if current_ltv is not None else None,
|
|
498
|
+
max_ltv=round(max_ltv, 6),
|
|
499
|
+
health_factor=round(account.liquidation_limit / account.debt, 4),
|
|
500
|
+
total_collateral_usd=(
|
|
501
|
+
round(account.collateral / COMET_PRICE_SCALE, 2) if in_usd else None
|
|
502
|
+
),
|
|
503
|
+
total_debt_usd=round(account.debt / COMET_PRICE_SCALE, 2) if in_usd else None,
|
|
504
|
+
ltv_usage_percent=round(ltv_usage, 2) if ltv_usage is not None else None,
|
|
505
|
+
)
|
|
506
|
+
|
|
507
|
+
|
|
440
508
|
@dataclass(frozen=True, slots=True)
|
|
441
509
|
class _EulerV2Account:
|
|
442
510
|
"""An EVC sub-account of the vault and the Euler vaults it may borrow from."""
|
|
@@ -574,6 +642,7 @@ class _LendingMarkets:
|
|
|
574
642
|
aave_v3: list[tuple[MarketId, str, ChecksumAddress]]
|
|
575
643
|
aave_v4: list[tuple[MarketId, str, ChecksumAddress]]
|
|
576
644
|
euler_v2: list[tuple[MarketId, str, _EulerV2Account]]
|
|
645
|
+
compound_v3: list[tuple[MarketId, str, ChecksumAddress]]
|
|
577
646
|
unreadable: list[UnreadableLendingMarket]
|
|
578
647
|
|
|
579
648
|
|
|
@@ -582,12 +651,14 @@ def _collect_lending_markets(
|
|
|
582
651
|
balance_fuse_market_ids: list[MarketId],
|
|
583
652
|
market_substrates: dict[MarketId, list[bytes]],
|
|
584
653
|
aave_pools: dict[MarketId, ChecksumAddress],
|
|
654
|
+
comets: dict[MarketId, ChecksumAddress],
|
|
585
655
|
) -> _LendingMarkets:
|
|
586
656
|
"""Pick the positions to read: Morpho substrates, Aave V3 markets with a Pool,
|
|
587
|
-
the Spokes of Aave V4 markets
|
|
588
|
-
market that may borrow but has no reader is listed
|
|
657
|
+
the Spokes of Aave V4 markets, the borrowing Euler V2 sub-accounts and Compound
|
|
658
|
+
V3 markets with a Comet. A market that may borrow but has no reader is listed
|
|
659
|
+
as unreadable."""
|
|
589
660
|
markets = _LendingMarkets(
|
|
590
|
-
morpho=[], aave_v3=[], aave_v4=[], euler_v2=[], unreadable=[]
|
|
661
|
+
morpho=[], aave_v3=[], aave_v4=[], euler_v2=[], compound_v3=[], unreadable=[]
|
|
591
662
|
)
|
|
592
663
|
|
|
593
664
|
for mid in balance_fuse_market_ids:
|
|
@@ -620,6 +691,18 @@ def _collect_lending_markets(
|
|
|
620
691
|
(mid, name, account)
|
|
621
692
|
for account in _euler_v2_borrow_accounts(substrates, vault)
|
|
622
693
|
)
|
|
694
|
+
elif mid in COMPOUND_V3_MARKET_IDS:
|
|
695
|
+
if comet := comets.get(mid):
|
|
696
|
+
markets.compound_v3.append((mid, name, comet))
|
|
697
|
+
else:
|
|
698
|
+
markets.unreadable.append(
|
|
699
|
+
UnreadableLendingMarket(
|
|
700
|
+
protocol="compound_v3",
|
|
701
|
+
market_id=mid,
|
|
702
|
+
market_name=name,
|
|
703
|
+
reason="the balance fuse names no Comet",
|
|
704
|
+
)
|
|
705
|
+
)
|
|
623
706
|
elif _can_borrow(mid, substrates):
|
|
624
707
|
markets.unreadable.append(
|
|
625
708
|
UnreadableLendingMarket(
|
|
@@ -633,6 +716,45 @@ def _collect_lending_markets(
|
|
|
633
716
|
return markets
|
|
634
717
|
|
|
635
718
|
|
|
719
|
+
def _health_reads(
|
|
720
|
+
ctx: Web3Context, vault: PlasmaVaultAddress, markets: _LendingMarkets
|
|
721
|
+
) -> list[Callable[[], LendingMarketHealth | UnreadableLendingMarket | None]]:
|
|
722
|
+
"""One read per position; Aave V3 health is account-level per Pool, so each
|
|
723
|
+
market reads its own."""
|
|
724
|
+
reads: list[Callable[[], LendingMarketHealth | UnreadableLendingMarket | None]] = []
|
|
725
|
+
if markets.morpho:
|
|
726
|
+
morpho_reader = MorphoReader(morpho_blue_address(ctx.chain_id))
|
|
727
|
+
reads += [
|
|
728
|
+
partial(
|
|
729
|
+
_compute_morpho_market_health,
|
|
730
|
+
ctx,
|
|
731
|
+
morpho_reader,
|
|
732
|
+
morpho_mid,
|
|
733
|
+
vault,
|
|
734
|
+
mid,
|
|
735
|
+
name,
|
|
736
|
+
)
|
|
737
|
+
for mid, name, morpho_mid in markets.morpho
|
|
738
|
+
]
|
|
739
|
+
reads += [
|
|
740
|
+
partial(_compute_aave_market_health, ctx, AaveV3Reader(pool), vault, mid, name)
|
|
741
|
+
for mid, name, pool in markets.aave_v3
|
|
742
|
+
]
|
|
743
|
+
reads += [
|
|
744
|
+
partial(_compute_aave_v4_market_health, ctx, spoke, vault, mid, name)
|
|
745
|
+
for mid, name, spoke in markets.aave_v4
|
|
746
|
+
]
|
|
747
|
+
reads += [
|
|
748
|
+
partial(_compute_euler_v2_account_health, ctx, account, mid, name)
|
|
749
|
+
for mid, name, account in markets.euler_v2
|
|
750
|
+
]
|
|
751
|
+
reads += [
|
|
752
|
+
partial(_compute_compound_v3_market_health, ctx, comet, vault, mid, name)
|
|
753
|
+
for mid, name, comet in markets.compound_v3
|
|
754
|
+
]
|
|
755
|
+
return reads
|
|
756
|
+
|
|
757
|
+
|
|
636
758
|
def fetch_vault_lending_health(
|
|
637
759
|
ctx: Web3Context,
|
|
638
760
|
vault: PlasmaVaultAddress,
|
|
@@ -640,6 +762,7 @@ def fetch_vault_lending_health(
|
|
|
640
762
|
balance_fuse_market_ids: list[MarketId],
|
|
641
763
|
market_substrates: dict[MarketId, list[bytes]],
|
|
642
764
|
aave_pools: dict[MarketId, ChecksumAddress] | None = None,
|
|
765
|
+
comets: dict[MarketId, ChecksumAddress] | None = None,
|
|
643
766
|
) -> VaultLendingHealth:
|
|
644
767
|
"""Fetch lending health for all lending markets in a vault.
|
|
645
768
|
|
|
@@ -655,68 +778,23 @@ def fetch_vault_lending_health(
|
|
|
655
778
|
entry is listed in ``unreadable``. Defaults to the chain's Core pool for AAVE_V3 only:
|
|
656
779
|
the Pools of Aave V3 Prime and SparkLend are known only to their
|
|
657
780
|
fuses.
|
|
781
|
+
comets: Map of Compound V3 market_id -> the Comet its balance fuse reads
|
|
782
|
+
(`CompoundV3FuseReader.comet`). A Compound V3 market without an entry
|
|
783
|
+
is listed in ``unreadable``.
|
|
658
784
|
"""
|
|
659
785
|
if aave_pools is None:
|
|
660
786
|
core_pool = AAVE_V3_POOL.get(ctx.chain_id)
|
|
661
787
|
aave_pools = {IporFusionMarkets.AAVE_V3: core_pool} if core_pool else {}
|
|
662
788
|
|
|
663
789
|
markets = _collect_lending_markets(
|
|
664
|
-
vault, balance_fuse_market_ids, market_substrates, aave_pools
|
|
790
|
+
vault, balance_fuse_market_ids, market_substrates, aave_pools, comets or {}
|
|
665
791
|
)
|
|
666
792
|
|
|
667
793
|
results: list[LendingMarketHealth] = []
|
|
668
794
|
unreadable = list(markets.unreadable)
|
|
669
795
|
|
|
670
796
|
with ThreadPoolExecutor() as pool:
|
|
671
|
-
futures = []
|
|
672
|
-
|
|
673
|
-
if markets.morpho:
|
|
674
|
-
morpho_reader = MorphoReader(morpho_blue_address(ctx.chain_id))
|
|
675
|
-
for ipor_mid, name, morpho_mid in markets.morpho:
|
|
676
|
-
futures.append(
|
|
677
|
-
pool.submit(
|
|
678
|
-
_compute_morpho_market_health,
|
|
679
|
-
ctx,
|
|
680
|
-
morpho_reader,
|
|
681
|
-
morpho_mid,
|
|
682
|
-
vault,
|
|
683
|
-
ipor_mid,
|
|
684
|
-
name,
|
|
685
|
-
)
|
|
686
|
-
)
|
|
687
|
-
|
|
688
|
-
# Aave V3 health is account-level per Pool, so each market reads its own.
|
|
689
|
-
for ipor_mid, name, aave_pool in markets.aave_v3:
|
|
690
|
-
futures.append(
|
|
691
|
-
pool.submit(
|
|
692
|
-
_compute_aave_market_health,
|
|
693
|
-
ctx,
|
|
694
|
-
AaveV3Reader(aave_pool),
|
|
695
|
-
vault,
|
|
696
|
-
ipor_mid,
|
|
697
|
-
name,
|
|
698
|
-
)
|
|
699
|
-
)
|
|
700
|
-
|
|
701
|
-
for ipor_mid, name, spoke in markets.aave_v4:
|
|
702
|
-
futures.append(
|
|
703
|
-
pool.submit(
|
|
704
|
-
_compute_aave_v4_market_health,
|
|
705
|
-
ctx,
|
|
706
|
-
spoke,
|
|
707
|
-
vault,
|
|
708
|
-
ipor_mid,
|
|
709
|
-
name,
|
|
710
|
-
)
|
|
711
|
-
)
|
|
712
|
-
|
|
713
|
-
for ipor_mid, name, account in markets.euler_v2:
|
|
714
|
-
futures.append(
|
|
715
|
-
pool.submit(
|
|
716
|
-
_compute_euler_v2_account_health, ctx, account, ipor_mid, name
|
|
717
|
-
)
|
|
718
|
-
)
|
|
719
|
-
|
|
797
|
+
futures = [pool.submit(read) for read in _health_reads(ctx, vault, markets)]
|
|
720
798
|
for fut in futures:
|
|
721
799
|
result = fut.result()
|
|
722
800
|
if result is None:
|