ipor-fusion 4.0.0.dev255__tar.gz → 4.0.0.dev263__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.dev255 → ipor_fusion-4.0.0.dev263}/AGENTS.md +3 -1
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/PKG-INFO +5 -2
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/README.md +4 -1
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/pyproject.toml +1 -1
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/skills/ipor-deploy-vault/SKILL.md +26 -16
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/__init__.py +8 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/fusion_factory.py +6 -6
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/guide/quickstart.md +26 -16
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/types.py +79 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_guide.py +48 -1
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_public_api.py +8 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_types_and_events.py +117 -1
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.claude-plugin/marketplace.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.claude-plugin/plugin.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.env.example +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.gemini/settings.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.git-blame-ignore-revs +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.github/workflows/cd.yml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.github/workflows/ci.yml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.github/workflows/commit-lint.yml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.github/workflows/notify-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.github/workflows/python-build.yml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.github/workflows/python-publish.yml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.github/workflows/release.yml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.github/workflows/report-slack.yml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.gitignore +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.pre-commit-config.yaml +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/.python-version +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/CHANGELOG.md +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/CLAUDE.md +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/CODEOWNERS +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/LICENSE +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/MIGRATION_4.md +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/build.sh +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/CONTRIBUTING.md +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/README.md +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/advanced_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/advanced_euler_v2_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/composed_hypercore_flow_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/crosschain_ccip_usdc_arbitrum_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/external_state_margin_leg_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/simple_aave_v3_supply_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/pytest.ini +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/scripts/commit-check.sh +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/scripts/crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/about.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cache.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/chains.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/changelog_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/config_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/config_store.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/main.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/market_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/options.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/oracle_mapping_view.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/vault_cmd.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/vault_health.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/vault_info_view.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/vault_markets_view.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/cli/vault_rendering.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/config/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/config/roles.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/access.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/address.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/context.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/contract.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/erc20.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/fuse.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/fuse_action.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/logs.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/multicall.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/oracle.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/simulation_result.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/codec.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/events.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/indexer.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/lane.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/quote.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/ccip/transport.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/discovery.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/errors.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/fuses/ccip.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/fuses/stargate.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/lane.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/logs.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/messages.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/simulation.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/stargate/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/stargate/contracts.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/stargate/lane.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/stargate/layerzero.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/stargate/transport.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/crosschain/transport.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/dependency_graph.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/entry_cli.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/entry_mcp.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/errors.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/explorer.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/field_docs.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/async_action.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/erc4626.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/events.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/external_state.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/external_state_event_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/fluid_instadapp.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/gearbox_v3.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/hypercore_event_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/merkl.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/fuses/universal.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/guide/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/guide/architecture.md +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/guide/glossary.md +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/guide/invariants.md +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/hypercore/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/market_ids.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/market_info.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/mcp/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/mcp/guide.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/mcp/models.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/mcp/server.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/morpho_api.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/py.typed +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/__init__.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/aave_v3.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/aave_v4.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/compound_v3.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/morpho.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/oracle_mapping_nodes.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/oracle_mapping_reader.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/position_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/ramses_v2.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/uniswap_v3.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/readers/unpriceable.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/substrates.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/validation.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/vault_data.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/vault_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/vault_info.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/vault_managers.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/vault_positions.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/vault_reads.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/UniswapV3UniversalRouter.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_crosschain_recovery.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_euler_v2.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_event_args.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_fake_rpc.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_foundry.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_golden.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_guide.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_hypercore_model.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_hypercore_shadow.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_live.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_oracle_mapping_fake.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_simulate.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/_validation.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/addresses.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/conftest.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/constants.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/hypercore_hip3_flow.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/hypercore_market55.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/meta_morpho_v1.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/meta_morpho_v1.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/meta_morpho_v2.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/meta_morpho_v2.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_api/market.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_api/vault_v1.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_api/vault_v2.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_api/vault_v2_not_found.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_blue.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_blue.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_blue_api_error.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_blue_api_error.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_blue_no_api.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/market_golden/morpho_blue_no_api.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/oracle_mapping_golden/mapping.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/oracle_mapping_golden/mapping.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/simulate_v1_request.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/clean.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/clean.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/clean.txt +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/deployment_error.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/deployment_error.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/deployment_error.txt +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/fetched.cli.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/fetched.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/fetched.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/full.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/full.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/full.txt +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/rich.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/rich.mcp.json +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/fixtures/vault_info_golden/rich.txt +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_about.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_access_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cache.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_chains.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_changelog.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_commands.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_config_store.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_helpers.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_lending_health.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_market_golden.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_market_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_mcp_parity.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_oracle_mapping_golden.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_pending_requests_scan.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_role_accounts.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_vault_info_golden.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_vault_predates_getters.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_cli_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_contract_call.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_contract_encoder.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_ccip_events.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_ccip_indexer.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_ccip_quote.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_chainlink.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_contracts.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_errors.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_lane.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_layering.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_readiness.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_readiness_report.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_crosschain_transport.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_docs_typing.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_erc20.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_error_hierarchy.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_examples_composed_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_examples_euler_looping_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_examples_vaults.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_explorer.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_external_state_events.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_external_state_executor.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_fee_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_fuse_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_fusion_instance.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_hypercore_deployment.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_hypercore_events.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_hypercore_flow.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_hypercore_live.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_hypercore_outcome.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_hypercore_readers.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_hypercore_simulation.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_logs.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_mcp_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_mcp_models.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_mcp_server.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_mcp_vault_validate.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_multicall.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_oracle.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_oracle_mapping.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_plasma_vault.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_public_type_reachability.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_reader_encoding.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_readiness_selection.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_revert_decoding.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_rewards_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_roles.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_sdk_layering.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_borrow_aave_v3_mainnet.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_claim_merkl_wrapper_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_claim_morpho_rewards.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_crosschain_canary.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_crosschain_hypercore.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_crosschain_hyperevm.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_crosschain_lifecycle.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_euler_v2_batch_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_euler_v2_credit_market_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_euler_v2_swap_deploy_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_euler_v2_swap_reconfigure_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_euler_v2_swap_registry_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_examples_arbitrum.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_examples_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_examples_crosschain.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_external_state_executor_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_fusion_factory_clone_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_looping_aave_v3_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_looping_morpho_blue_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_morpho_blue.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_pilot_v3.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_pilot_v4_uniswap.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_pilot_v5_ramses.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_pilot_v5_scheduled.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_plasma_vault_setters_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_readers_integration.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_release_funds.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_swap_on_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulate_vault_from_scratch_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulation_errors.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_simulation_observation.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_solidity_compiler.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_solidity_mirrors.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_substrates.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_unpriceable_tokens.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_validation.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_vault_data_block.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_vault_dep_graph.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_vault_info_fetched_golden.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_vault_info_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_vault_info_onchain_base_no_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_vault_reconciliation_onchain_base.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_vault_simulator_blocks.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_web3_context.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/test_withdraw_manager.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/typed_client/consumer.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/tests/typed_client/rejected.py +0 -0
- {ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/uv.lock +0 -0
|
@@ -419,7 +419,9 @@ or examples.
|
|
|
419
419
|
round re-resolves it. Labels only name calls in `result.calls` and failures.
|
|
420
420
|
Integration tests and examples use it instead of a local node.
|
|
421
421
|
- Amounts are raw on-chain integers; `types.py` `NewType`s (`Amount`, `Shares`,
|
|
422
|
-
`MarketId`, ...) name the unit, and nothing scales by decimals
|
|
422
|
+
`MarketId`, ...) name the unit, and nothing scales by decimals except the exact
|
|
423
|
+
boundary converters `parse_amount` / `format_amount` (and the `*_shares` pair):
|
|
424
|
+
decimal text in, raw integer out, no float ever.
|
|
423
425
|
- Three address roles are nominal: `PlasmaVaultAddress`, `FuseAddress` and
|
|
424
426
|
`AccessManagerAddress` (NewTypes of `ChecksumAddress`). Their wrappers, getters and
|
|
425
427
|
records return them, so a vault, a fuse and an access manager cannot be passed for
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: ipor-fusion
|
|
3
|
-
Version: 4.0.0.
|
|
3
|
+
Version: 4.0.0.dev263
|
|
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
|
|
@@ -170,7 +170,10 @@ Fuse, factory and manager addresses per chain are published in
|
|
|
170
170
|
[ipor-abi](https://github.com/IPOR-Labs/ipor-abi) (`mainnet/mainnet-<chain>-fusion/addresses.json`).
|
|
171
171
|
A fuse must also be registered on the vault; `vault.get_fuses().call(ctx)` lists the registered ones.
|
|
172
172
|
|
|
173
|
-
Amounts are raw on-chain integers (`Amount`, `Shares` in `ipor_fusion.types`); the SDK
|
|
173
|
+
Amounts are raw on-chain integers (`Amount`, `Shares` in `ipor_fusion.types`); the SDK scales by decimals
|
|
174
|
+
only in explicit boundary converters.
|
|
175
|
+
`parse_amount("1.5", Decimals(6))` and `format_amount(Amount(1_500_000), Decimals(6))` convert exactly at the
|
|
176
|
+
boundary (no floats, no rounding; `parse_shares` / `format_shares` for shares at the share token's decimals).
|
|
174
177
|
|
|
175
178
|
### Read, send, or simulate
|
|
176
179
|
|
|
@@ -122,7 +122,10 @@ Fuse, factory and manager addresses per chain are published in
|
|
|
122
122
|
[ipor-abi](https://github.com/IPOR-Labs/ipor-abi) (`mainnet/mainnet-<chain>-fusion/addresses.json`).
|
|
123
123
|
A fuse must also be registered on the vault; `vault.get_fuses().call(ctx)` lists the registered ones.
|
|
124
124
|
|
|
125
|
-
Amounts are raw on-chain integers (`Amount`, `Shares` in `ipor_fusion.types`); the SDK
|
|
125
|
+
Amounts are raw on-chain integers (`Amount`, `Shares` in `ipor_fusion.types`); the SDK scales by decimals
|
|
126
|
+
only in explicit boundary converters.
|
|
127
|
+
`parse_amount("1.5", Decimals(6))` and `format_amount(Amount(1_500_000), Decimals(6))` convert exactly at the
|
|
128
|
+
boundary (no floats, no rounding; `parse_shares` / `format_shares` for shares at the share token's decimals).
|
|
126
129
|
|
|
127
130
|
### Read, send, or simulate
|
|
128
131
|
|
|
@@ -204,22 +204,32 @@ Notes on the walk:
|
|
|
204
204
|
so you recognise and avoid it. Verify against `ipor-abi` before use; the
|
|
205
205
|
registry is the source of truth and is regenerated on release.
|
|
206
206
|
|
|
207
|
-
| Chain | Chain id | `IporFusionFactoryProxy` (use) | `IporFusionFactoryImpl` (reverts) | Verified |
|
|
208
|
-
|
|
209
|
-
| Ethereum | 1 | `0xcd05909C4A1F8E501e4ED554cEF4Ed5E48D9b852` | `
|
|
210
|
-
|
|
|
211
|
-
|
|
|
212
|
-
|
|
|
213
|
-
|
|
|
214
|
-
|
|
|
215
|
-
|
|
|
216
|
-
|
|
|
217
|
-
|
|
|
218
|
-
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
207
|
+
| Chain | Chain id | `IporFusionFactoryProxy` (use) | `IporFusionFactoryImpl` (reverts) | Vault tooling | Verified |
|
|
208
|
+
|---|---|---|---|---|---|
|
|
209
|
+
| Ethereum | 1 | `0xcd05909C4A1F8E501e4ED554cEF4Ed5E48D9b852` | `0x14d120C365Debd920eaDf0a7AC31e659Bc58217b` | validated | implementation slot |
|
|
210
|
+
| Flare | 14 | `0xE75F3565D67645775351A9886F2b598f07d1860B` | `0x6C1ff6eBf5e92Dbc5591E7cCF455829De9C46579` | factory only | implementation slot |
|
|
211
|
+
| Unichain | 130 | `0xC9b4E839e86284C558791C13Bda97999fc49aF63` | `0x73c7CA802403BB21e9608C937c556C04d5eeBAD6` | validated | implementation slot |
|
|
212
|
+
| Monad | 143 | `0x62DFfe8bCaaf7960f858a4f7dDC83cc98F04cEDC` | `0x1017f0032460B3c8FBB92Bfd350F708Ff6229137` | validated | implementation slot |
|
|
213
|
+
| TAC | 239 | `0x26b5561E2E0e7d7977431E92740903Ef3cB7194b` | `0x7DDd0bBB59eFB4b7791cE5E1Cf1587F083aE4Ef5` | factory only | implementation slot |
|
|
214
|
+
| HyperEVM | 999 | `0x6bBc827F34b4e862d15215ABd4AC0E3886181665` | `0x010430cbdE2Bb8ACC48D7aDfbEb99812E83f1156` | validated | implementation slot |
|
|
215
|
+
| Botanix | 3637 | `0x7c9857f22D0cc6523C8e88BFDCbf411AB8300fF5` | `0xddb0EFB2a7a5C02e01b5A1f85C0a1110d68EeC26` | factory only | registry only |
|
|
216
|
+
| Robinhood | 4663 | `0xDF7A590b60072476E355A8EfF33e4872440bDc7C` | `0x9d897beA78F8747d8f9C45d5734089ca7225AE90` | validated | implementation slot |
|
|
217
|
+
| Base | 8453 | `0x1455717668fA96534f675856347A973fA907e922` | `0x378fEb2E96082FB965E2BB922AEE484d07c14014` | validated | implementation slot |
|
|
218
|
+
| Plasma | 9745 | `0x70d41759FBF90fB63c88197217cB08F93a1c65CB` | `0x346DA190c60d6101B77DA613a252c7aE25A7a120` | validated | implementation slot |
|
|
219
|
+
| Arbitrum | 42161 | `0x134fCAce7a2C7Ef3dF2479B62f03ddabAEa922d5` | `0x86C8Ea8800EB6bc8C846c3e0230178520a0ED721` | validated | implementation slot |
|
|
220
|
+
| Avalanche | 43114 | `0xa00b6379833D77fA9C9497b32dae00dF39Ac751e` | `0x0f358Bb3d14AB911dBfAF4d9061097e7F5Cf123F` | validated | implementation slot |
|
|
221
|
+
| Ink | 57073 | `0xEC53f69Bd1D991a2F99e96DE66E81D0E42A61D8D` | `0xEF774B9767cC9FC813A2b595BE870A13D5B367C0` | validated | implementation slot |
|
|
222
|
+
| Katana | 747474 | `0xc29b8D591d6a3f109Ca7ba384F2e00162866D37B` | `0x4a4De6e86AD0d0546F55B595cA75f55803D940bA` | validated | implementation slot |
|
|
223
|
+
|
|
224
|
+
A deployed factory is not the same as supported tooling. "Validated" chains are
|
|
225
|
+
`SUPPORTED_CHAIN_IDS` (`ipor_fusion.chains`): `fusion vault info`/`validate`
|
|
226
|
+
and `fetch_vault_data` run there. On a "factory only" chain `clone()` works,
|
|
227
|
+
but the vault tooling raises `UnsupportedChainError` until the chain is
|
|
228
|
+
validated. "Implementation slot" means the proxy's EIP-1967 implementation
|
|
229
|
+
slot was read on chain and matches the registry's `IporFusionFactoryImpl`;
|
|
230
|
+
"registry only" means the pair comes from `ipor-abi` without an on-chain read.
|
|
231
|
+
The factory implementations are upgraded in place, so the implementation
|
|
232
|
+
column changes with releases while the proxy stays.
|
|
223
233
|
|
|
224
234
|
Fuse addresses are not in the SDK. Resolve them by registry name and chain
|
|
225
235
|
in `ipor-abi` (`SupplyFuseAaveV3`, `BalanceFuseAaveV3`, ...), or with the
|
|
@@ -333,11 +333,15 @@ from ipor_fusion.types import (
|
|
|
333
333
|
TokenId,
|
|
334
334
|
TxHash,
|
|
335
335
|
Verdict,
|
|
336
|
+
format_amount,
|
|
337
|
+
format_shares,
|
|
336
338
|
parse_access_manager_address,
|
|
339
|
+
parse_amount,
|
|
337
340
|
parse_fuse_address,
|
|
338
341
|
parse_hex_address,
|
|
339
342
|
parse_morpho_market_id,
|
|
340
343
|
parse_plasma_vault_address,
|
|
344
|
+
parse_shares,
|
|
341
345
|
parse_tx_hash,
|
|
342
346
|
)
|
|
343
347
|
from ipor_fusion.validation import (
|
|
@@ -617,6 +621,10 @@ __all__ = [
|
|
|
617
621
|
"parse_plasma_vault_address",
|
|
618
622
|
"parse_morpho_market_id",
|
|
619
623
|
"parse_tx_hash",
|
|
624
|
+
"parse_amount",
|
|
625
|
+
"parse_shares",
|
|
626
|
+
"format_amount",
|
|
627
|
+
"format_shares",
|
|
620
628
|
"Price",
|
|
621
629
|
"Period",
|
|
622
630
|
"MAX_UINT256",
|
{ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/src/ipor_fusion/core/fusion_factory.py
RENAMED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"""IporFusionFactoryProxy wrapper — deploys a full Fusion vault stack
|
|
2
2
|
(plasmaVault + accessManager + 6 managers) in a single tx.
|
|
3
3
|
|
|
4
|
-
Deployed signature on BASE (verified 2026-05-12
|
|
4
|
+
Deployed signature on BASE (verified against the impl bytecode on 2026-05-12,
|
|
5
|
+
and on 2026-10-23 for the upgraded impl 0x378fEb2E96082FB965E2BB922AEE484d07c14014):
|
|
5
6
|
clone(string assetName_, string assetSymbol_, address underlyingToken_,
|
|
6
7
|
uint256 redemptionDelayInSeconds_, address owner_,
|
|
7
8
|
uint256 daoFeePackageIndex_) → FusionInstance
|
|
8
9
|
|
|
9
|
-
Note: the ipor-abi registry
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
when they disagree.
|
|
10
|
+
Note: the ipor-abi registry has published a 5-arg shape (no
|
|
11
|
+
daoFeePackageIndex); both the earlier impl 0x610152a79be7f2aa3aa70520c9331c18fe8d33b7
|
|
12
|
+
and the current one expose only the 6-arg variant (selector 0x8697b10a). Always
|
|
13
|
+
trust the impl bytecode over the registry when they disagree.
|
|
14
14
|
|
|
15
15
|
`clone()` is a write — call `.send(ctx)` for a real tx, then decode the
|
|
16
16
|
created addresses from its receipt with `factory.decode_clone_receipt(receipt)`.
|
|
@@ -119,22 +119,32 @@ Notes on the walk:
|
|
|
119
119
|
so you recognise and avoid it. Verify against `ipor-abi` before use; the
|
|
120
120
|
registry is the source of truth and is regenerated on release.
|
|
121
121
|
|
|
122
|
-
| Chain | Chain id | `IporFusionFactoryProxy` (use) | `IporFusionFactoryImpl` (reverts) | Verified |
|
|
123
|
-
|
|
124
|
-
| Ethereum | 1 | `0xcd05909C4A1F8E501e4ED554cEF4Ed5E48D9b852` | `
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
|
|
|
130
|
-
|
|
|
131
|
-
|
|
|
132
|
-
|
|
|
133
|
-
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
122
|
+
| Chain | Chain id | `IporFusionFactoryProxy` (use) | `IporFusionFactoryImpl` (reverts) | Vault tooling | Verified |
|
|
123
|
+
|---|---|---|---|---|---|
|
|
124
|
+
| Ethereum | 1 | `0xcd05909C4A1F8E501e4ED554cEF4Ed5E48D9b852` | `0x14d120C365Debd920eaDf0a7AC31e659Bc58217b` | validated | implementation slot |
|
|
125
|
+
| Flare | 14 | `0xE75F3565D67645775351A9886F2b598f07d1860B` | `0x6C1ff6eBf5e92Dbc5591E7cCF455829De9C46579` | factory only | implementation slot |
|
|
126
|
+
| Unichain | 130 | `0xC9b4E839e86284C558791C13Bda97999fc49aF63` | `0x73c7CA802403BB21e9608C937c556C04d5eeBAD6` | validated | implementation slot |
|
|
127
|
+
| Monad | 143 | `0x62DFfe8bCaaf7960f858a4f7dDC83cc98F04cEDC` | `0x1017f0032460B3c8FBB92Bfd350F708Ff6229137` | validated | implementation slot |
|
|
128
|
+
| TAC | 239 | `0x26b5561E2E0e7d7977431E92740903Ef3cB7194b` | `0x7DDd0bBB59eFB4b7791cE5E1Cf1587F083aE4Ef5` | factory only | implementation slot |
|
|
129
|
+
| HyperEVM | 999 | `0x6bBc827F34b4e862d15215ABd4AC0E3886181665` | `0x010430cbdE2Bb8ACC48D7aDfbEb99812E83f1156` | validated | implementation slot |
|
|
130
|
+
| Botanix | 3637 | `0x7c9857f22D0cc6523C8e88BFDCbf411AB8300fF5` | `0xddb0EFB2a7a5C02e01b5A1f85C0a1110d68EeC26` | factory only | registry only |
|
|
131
|
+
| Robinhood | 4663 | `0xDF7A590b60072476E355A8EfF33e4872440bDc7C` | `0x9d897beA78F8747d8f9C45d5734089ca7225AE90` | validated | implementation slot |
|
|
132
|
+
| Base | 8453 | `0x1455717668fA96534f675856347A973fA907e922` | `0x378fEb2E96082FB965E2BB922AEE484d07c14014` | validated | implementation slot |
|
|
133
|
+
| Plasma | 9745 | `0x70d41759FBF90fB63c88197217cB08F93a1c65CB` | `0x346DA190c60d6101B77DA613a252c7aE25A7a120` | validated | implementation slot |
|
|
134
|
+
| Arbitrum | 42161 | `0x134fCAce7a2C7Ef3dF2479B62f03ddabAEa922d5` | `0x86C8Ea8800EB6bc8C846c3e0230178520a0ED721` | validated | implementation slot |
|
|
135
|
+
| Avalanche | 43114 | `0xa00b6379833D77fA9C9497b32dae00dF39Ac751e` | `0x0f358Bb3d14AB911dBfAF4d9061097e7F5Cf123F` | validated | implementation slot |
|
|
136
|
+
| Ink | 57073 | `0xEC53f69Bd1D991a2F99e96DE66E81D0E42A61D8D` | `0xEF774B9767cC9FC813A2b595BE870A13D5B367C0` | validated | implementation slot |
|
|
137
|
+
| Katana | 747474 | `0xc29b8D591d6a3f109Ca7ba384F2e00162866D37B` | `0x4a4De6e86AD0d0546F55B595cA75f55803D940bA` | validated | implementation slot |
|
|
138
|
+
|
|
139
|
+
A deployed factory is not the same as supported tooling. "Validated" chains are
|
|
140
|
+
`SUPPORTED_CHAIN_IDS` (`ipor_fusion.chains`): `fusion vault info`/`validate`
|
|
141
|
+
and `fetch_vault_data` run there. On a "factory only" chain `clone()` works,
|
|
142
|
+
but the vault tooling raises `UnsupportedChainError` until the chain is
|
|
143
|
+
validated. "Implementation slot" means the proxy's EIP-1967 implementation
|
|
144
|
+
slot was read on chain and matches the registry's `IporFusionFactoryImpl`;
|
|
145
|
+
"registry only" means the pair comes from `ipor-abi` without an on-chain read.
|
|
146
|
+
The factory implementations are upgraded in place, so the implementation
|
|
147
|
+
column changes with releases while the proxy stays.
|
|
138
148
|
|
|
139
149
|
Fuse addresses are not in the SDK. Resolve them by registry name and chain
|
|
140
150
|
in `ipor-abi` (`SupplyFuseAaveV3`, `BalanceFuseAaveV3`, ...), or with the
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from dataclasses import dataclass
|
|
2
3
|
from typing import ClassVar, Literal, NewType, TypeAlias
|
|
3
4
|
|
|
@@ -196,3 +197,81 @@ def parse_fuse_address(value: str | bytes) -> FuseAddress:
|
|
|
196
197
|
def parse_access_manager_address(value: str | bytes) -> AccessManagerAddress:
|
|
197
198
|
"""An access manager's address, checksummed; see `parse_plasma_vault_address`."""
|
|
198
199
|
return AccessManagerAddress(_checksum(value))
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# ASCII digits only: ``\d`` would also take other scripts' digits, which int() reads.
|
|
203
|
+
_DECIMAL_TEXT = re.compile(r"([0-9]*)(?:\.([0-9]*))?")
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
_UINT256_DIGITS = len(str(MAX_UINT256))
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _check_decimals(decimals: Decimals) -> None:
|
|
210
|
+
if not 0 <= decimals <= 255:
|
|
211
|
+
raise ValueError(f"decimals must be 0..255 (ERC-20 uint8), got {decimals}")
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _parse_units(text: str, decimals: Decimals, what: str) -> int:
|
|
215
|
+
if not isinstance(text, str):
|
|
216
|
+
raise TypeError(
|
|
217
|
+
f"{what} must be text, not {type(text).__name__}: floats lose precision"
|
|
218
|
+
)
|
|
219
|
+
_check_decimals(decimals)
|
|
220
|
+
match = _DECIMAL_TEXT.fullmatch(text.strip())
|
|
221
|
+
if match is None or not (match.group(1) or match.group(2)):
|
|
222
|
+
raise ValueError(f"not a decimal {what}: {text!r}")
|
|
223
|
+
whole, fraction = match.group(1).lstrip("0"), match.group(2) or ""
|
|
224
|
+
if len(fraction) > decimals:
|
|
225
|
+
raise ValueError(
|
|
226
|
+
f"{what} {text!r} has {len(fraction)} fractional digits,"
|
|
227
|
+
f" more than the {decimals} the token carries"
|
|
228
|
+
)
|
|
229
|
+
# Bounded before int(): a longer whole part overflows uint256 at any scale.
|
|
230
|
+
if len(whole) > _UINT256_DIGITS:
|
|
231
|
+
raise ValueError(f"{what} {text!r} exceeds uint256")
|
|
232
|
+
value = int(whole + fraction.ljust(decimals, "0") or "0")
|
|
233
|
+
if value > MAX_UINT256:
|
|
234
|
+
raise ValueError(f"{what} {text!r} exceeds uint256")
|
|
235
|
+
return value
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _format_units(value: int, decimals: Decimals, what: str) -> str:
|
|
239
|
+
if not 0 <= value <= MAX_UINT256:
|
|
240
|
+
raise ValueError(f"{what} must be within uint256, got {value}")
|
|
241
|
+
_check_decimals(decimals)
|
|
242
|
+
whole, fraction = divmod(value, 10**decimals)
|
|
243
|
+
if fraction == 0:
|
|
244
|
+
return str(whole)
|
|
245
|
+
return f"{whole}.{str(fraction).zfill(decimals).rstrip('0')}"
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def parse_amount(text: str, decimals: Decimals) -> Amount:
|
|
249
|
+
"""The raw `Amount` of ``text`` token units at ``decimals``, exactly:
|
|
250
|
+
``parse_amount("1.5", Decimals(6))`` is ``Amount(1_500_000)``.
|
|
251
|
+
|
|
252
|
+
``text`` is digits with at most one ``.`` (surrounding whitespace ignored);
|
|
253
|
+
no sign, exponent or separators. ``decimals`` is 0..255, an ERC-20 uint8.
|
|
254
|
+
Raises ``ValueError`` for anything else, for more fractional digits than
|
|
255
|
+
``decimals`` (nothing is rounded) and for a value above uint256; ``TypeError`` for a non-string, so a float is never
|
|
256
|
+
accepted. Inverse of `format_amount`.
|
|
257
|
+
"""
|
|
258
|
+
return Amount(_parse_units(text, decimals, "amount"))
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def parse_shares(text: str, decimals: Decimals) -> Shares:
|
|
262
|
+
"""`parse_amount` for vault shares at the share token's ``decimals``
|
|
263
|
+
(`PlasmaVault.decimals`, not the asset's)."""
|
|
264
|
+
return Shares(_parse_units(text, decimals, "shares"))
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def format_amount(amount: Amount, decimals: Decimals) -> str:
|
|
268
|
+
"""``amount`` in token units as exact decimal text, no trailing zeros:
|
|
269
|
+
``format_amount(Amount(1_500_000), Decimals(6))`` is ``"1.5"``; a whole
|
|
270
|
+
number has no ``.``. Raises ``ValueError`` on an amount outside uint256 or
|
|
271
|
+
``decimals`` outside 0..255. Inverse of `parse_amount`."""
|
|
272
|
+
return _format_units(amount, decimals, "amount")
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def format_shares(shares: Shares, decimals: Decimals) -> str:
|
|
276
|
+
"""`format_amount` for vault shares."""
|
|
277
|
+
return _format_units(shares, decimals, "shares")
|
|
@@ -10,7 +10,14 @@ from _euler_v2 import BASE_FUSION_FACTORY
|
|
|
10
10
|
from _guide import GUIDE_ADDRESSES
|
|
11
11
|
from addresses import BASE_USDC
|
|
12
12
|
|
|
13
|
-
from ipor_fusion import
|
|
13
|
+
from ipor_fusion import (
|
|
14
|
+
CHAIN_NAMES,
|
|
15
|
+
ERC20,
|
|
16
|
+
SUPPORTED_CHAIN_IDS,
|
|
17
|
+
AccessManager,
|
|
18
|
+
Call,
|
|
19
|
+
PlasmaVault,
|
|
20
|
+
)
|
|
14
21
|
from ipor_fusion.core import FusionFactory
|
|
15
22
|
from ipor_fusion.fuses import AaveV3SupplyFuse
|
|
16
23
|
from ipor_fusion.guide import (
|
|
@@ -21,6 +28,7 @@ from ipor_fusion.guide import (
|
|
|
21
28
|
RESOURCES,
|
|
22
29
|
guide_text,
|
|
23
30
|
)
|
|
31
|
+
from ipor_fusion.types import ChainId
|
|
24
32
|
|
|
25
33
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
26
34
|
SKILL_DIR = REPO_ROOT / "skills" / "ipor-deploy-vault"
|
|
@@ -49,6 +57,28 @@ PUBLIC_REPOS = {
|
|
|
49
57
|
_URL = re.compile(r"https?://([A-Za-z0-9.-]+)(?::\d+)?(/[^\s)`>\"']*)?")
|
|
50
58
|
_FRONTMATTER = re.compile(r"\A---\n(.*?)\n---\n", re.DOTALL)
|
|
51
59
|
_PY_BLOCK = re.compile(r"```python\n(.*?)```", re.DOTALL)
|
|
60
|
+
# Chains with an IporFusionFactoryProxy in ipor-abi (mainnet-<chain>-fusion).
|
|
61
|
+
FACTORY_CHAINS = {
|
|
62
|
+
1,
|
|
63
|
+
14,
|
|
64
|
+
130,
|
|
65
|
+
143,
|
|
66
|
+
239,
|
|
67
|
+
999,
|
|
68
|
+
3637,
|
|
69
|
+
4663,
|
|
70
|
+
8453,
|
|
71
|
+
9745,
|
|
72
|
+
42161,
|
|
73
|
+
43114,
|
|
74
|
+
57073,
|
|
75
|
+
747474,
|
|
76
|
+
}
|
|
77
|
+
_FACTORY_ROW = re.compile(
|
|
78
|
+
r"^\| (\w+) \| (\d+) \| `(0x[0-9a-fA-F]{40})` \| `(0x[0-9a-fA-F]{40})` \| "
|
|
79
|
+
r"(validated|factory only) \| (implementation slot|registry only) \|$",
|
|
80
|
+
re.MULTILINE,
|
|
81
|
+
)
|
|
52
82
|
|
|
53
83
|
|
|
54
84
|
def _public_texts() -> dict[str, str]:
|
|
@@ -89,6 +119,23 @@ class TestResources:
|
|
|
89
119
|
assert GUIDE_ADDRESSES["USDC"] == BASE_USDC
|
|
90
120
|
assert {"SUPPLY_FUSE", "BALANCE_FUSE"} <= set(GUIDE_ADDRESSES)
|
|
91
121
|
|
|
122
|
+
def test_factory_table_tooling_column_is_the_supported_chain_set(self):
|
|
123
|
+
section = QUICKSTART.text.split("## Factory proxies per chain", 1)[1]
|
|
124
|
+
body = [
|
|
125
|
+
line
|
|
126
|
+
for line in section.splitlines()
|
|
127
|
+
if line.startswith("| ") and not line.startswith("| Chain |")
|
|
128
|
+
]
|
|
129
|
+
rows = _FACTORY_ROW.findall("\n".join(body))
|
|
130
|
+
assert len(rows) == len(body), "every table row parses"
|
|
131
|
+
assert {int(row[1]) for row in rows} == FACTORY_CHAINS
|
|
132
|
+
ids = [int(row[1]) for row in rows]
|
|
133
|
+
assert ids == sorted(set(ids)), "one row per chain, by chain id"
|
|
134
|
+
for name, chain_id, *_ in rows:
|
|
135
|
+
assert CHAIN_NAMES[ChainId(int(chain_id))] == name.lower()
|
|
136
|
+
validated = {int(row[1]) for row in rows if row[4] == "validated"}
|
|
137
|
+
assert validated == set(SUPPORTED_CHAIN_IDS)
|
|
138
|
+
|
|
92
139
|
def test_invariants_name_every_deploy_path_revert(self):
|
|
93
140
|
text = INVARIANTS.text
|
|
94
141
|
for selector, name in [
|
|
@@ -367,7 +367,9 @@ _ALL_SNAPSHOT: dict[str, frozenset[str]] = {
|
|
|
367
367
|
"find_creation_block",
|
|
368
368
|
"find_markets_missing_erc20_dependency",
|
|
369
369
|
"find_orphan_fuse_markets",
|
|
370
|
+
"format_amount",
|
|
370
371
|
"format_market_label",
|
|
372
|
+
"format_shares",
|
|
371
373
|
"get_contract_name",
|
|
372
374
|
"get_deployment_tx",
|
|
373
375
|
"get_logs_adaptive",
|
|
@@ -377,10 +379,12 @@ _ALL_SNAPSHOT: dict[str, frozenset[str]] = {
|
|
|
377
379
|
"morpho_blue_address",
|
|
378
380
|
"package_version",
|
|
379
381
|
"parse_access_manager_address",
|
|
382
|
+
"parse_amount",
|
|
380
383
|
"parse_fuse_address",
|
|
381
384
|
"parse_hex_address",
|
|
382
385
|
"parse_morpho_market_id",
|
|
383
386
|
"parse_plasma_vault_address",
|
|
387
|
+
"parse_shares",
|
|
384
388
|
"parse_tx_hash",
|
|
385
389
|
"price_oracle_middleware",
|
|
386
390
|
"read_changelog",
|
|
@@ -1107,11 +1111,15 @@ _MODULE_PATH_SNAPSHOT: dict[str, frozenset[str]] = {
|
|
|
1107
1111
|
"TxHash",
|
|
1108
1112
|
"Verdict",
|
|
1109
1113
|
"ZERO_ADDRESS",
|
|
1114
|
+
"format_amount",
|
|
1115
|
+
"format_shares",
|
|
1110
1116
|
"parse_access_manager_address",
|
|
1117
|
+
"parse_amount",
|
|
1111
1118
|
"parse_fuse_address",
|
|
1112
1119
|
"parse_hex_address",
|
|
1113
1120
|
"parse_morpho_market_id",
|
|
1114
1121
|
"parse_plasma_vault_address",
|
|
1122
|
+
"parse_shares",
|
|
1115
1123
|
"parse_tx_hash",
|
|
1116
1124
|
}
|
|
1117
1125
|
),
|
|
@@ -6,7 +6,7 @@ from hexbytes import HexBytes
|
|
|
6
6
|
from web3 import Web3
|
|
7
7
|
|
|
8
8
|
from ipor_fusion.fuses.events import extract_events
|
|
9
|
-
from ipor_fusion.types import Amount, Decimals, Price
|
|
9
|
+
from ipor_fusion.types import MAX_UINT256, Amount, Decimals, Price, Shares
|
|
10
10
|
|
|
11
11
|
ADDR = Web3.to_checksum_address("0x1111111111111111111111111111111111111111")
|
|
12
12
|
|
|
@@ -155,3 +155,119 @@ class TestRoleParsers:
|
|
|
155
155
|
assert parser(bytes.fromhex(self.LOWER[2:])) == checksum
|
|
156
156
|
with pytest.raises(ValueError):
|
|
157
157
|
parser("0x1234")
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class TestAmountText:
|
|
161
|
+
@pytest.mark.parametrize(
|
|
162
|
+
("text", "decimals", "raw"),
|
|
163
|
+
[
|
|
164
|
+
("1.5", 6, 1_500_000),
|
|
165
|
+
("0.000001", 6, 1),
|
|
166
|
+
("1", 18, 10**18),
|
|
167
|
+
("1.", 6, 1_000_000),
|
|
168
|
+
(".5", 6, 500_000),
|
|
169
|
+
(" 42 ", 0, 42),
|
|
170
|
+
("0", 6, 0),
|
|
171
|
+
("1.000000", 6, 1_000_000),
|
|
172
|
+
(str(MAX_UINT256), 0, MAX_UINT256),
|
|
173
|
+
(
|
|
174
|
+
"115792089237316195423570985008687907853269984665640564039457.584007913129639935",
|
|
175
|
+
18,
|
|
176
|
+
MAX_UINT256,
|
|
177
|
+
),
|
|
178
|
+
],
|
|
179
|
+
)
|
|
180
|
+
def test_parse_amount_is_exact(self, text, decimals, raw):
|
|
181
|
+
from ipor_fusion import parse_amount
|
|
182
|
+
|
|
183
|
+
assert parse_amount(text, Decimals(decimals)) == raw
|
|
184
|
+
|
|
185
|
+
@pytest.mark.parametrize(
|
|
186
|
+
"text",
|
|
187
|
+
[
|
|
188
|
+
"",
|
|
189
|
+
".",
|
|
190
|
+
"-1",
|
|
191
|
+
"+1",
|
|
192
|
+
"1e6",
|
|
193
|
+
"1,000",
|
|
194
|
+
"1_000",
|
|
195
|
+
"1.5.0",
|
|
196
|
+
"0x10",
|
|
197
|
+
"1 0",
|
|
198
|
+
"nan",
|
|
199
|
+
"\u0663",
|
|
200
|
+
"\uff11.5",
|
|
201
|
+
],
|
|
202
|
+
)
|
|
203
|
+
def test_parse_amount_rejects_anything_but_plain_decimal_text(self, text):
|
|
204
|
+
from ipor_fusion import parse_amount
|
|
205
|
+
|
|
206
|
+
with pytest.raises(ValueError, match="not a decimal amount"):
|
|
207
|
+
parse_amount(text, Decimals(6))
|
|
208
|
+
|
|
209
|
+
def test_parse_amount_never_rounds(self):
|
|
210
|
+
from ipor_fusion import parse_amount
|
|
211
|
+
|
|
212
|
+
with pytest.raises(ValueError, match="7 fractional digits"):
|
|
213
|
+
parse_amount("1.0000001", Decimals(6))
|
|
214
|
+
|
|
215
|
+
def test_parse_amount_rejects_uint256_overflow_and_floats(self):
|
|
216
|
+
from ipor_fusion import parse_amount
|
|
217
|
+
|
|
218
|
+
with pytest.raises(ValueError, match="exceeds uint256"):
|
|
219
|
+
parse_amount(str(MAX_UINT256 + 1), Decimals(0))
|
|
220
|
+
with pytest.raises(TypeError, match="floats lose precision"):
|
|
221
|
+
parse_amount(1.5, Decimals(6))
|
|
222
|
+
with pytest.raises(ValueError, match="decimals"):
|
|
223
|
+
parse_amount("1", Decimals(-1))
|
|
224
|
+
with pytest.raises(ValueError, match="0..255"):
|
|
225
|
+
parse_amount("1", Decimals(256))
|
|
226
|
+
|
|
227
|
+
def test_parse_amount_bounds_digits_before_converting(self):
|
|
228
|
+
from ipor_fusion import parse_amount
|
|
229
|
+
|
|
230
|
+
# Leading zeros are not significant, past Python's int() digit limit too.
|
|
231
|
+
assert parse_amount("0" * 5000 + "1", Decimals(0)) == 1
|
|
232
|
+
with pytest.raises(ValueError, match="exceeds uint256"):
|
|
233
|
+
parse_amount("1" * 5000, Decimals(0))
|
|
234
|
+
assert parse_amount("0." + "0" * 254 + "1", Decimals(255)) == 1
|
|
235
|
+
|
|
236
|
+
@pytest.mark.parametrize(
|
|
237
|
+
("raw", "decimals", "text"),
|
|
238
|
+
[
|
|
239
|
+
(1_500_000, 6, "1.5"),
|
|
240
|
+
(1, 6, "0.000001"),
|
|
241
|
+
(10**18, 18, "1"),
|
|
242
|
+
(0, 6, "0"),
|
|
243
|
+
(42, 0, "42"),
|
|
244
|
+
(123_456_789, 4, "12345.6789"),
|
|
245
|
+
(
|
|
246
|
+
MAX_UINT256,
|
|
247
|
+
18,
|
|
248
|
+
"115792089237316195423570985008687907853269984665640564039457.584007913129639935",
|
|
249
|
+
),
|
|
250
|
+
],
|
|
251
|
+
)
|
|
252
|
+
def test_format_amount_round_trips(self, raw, decimals, text):
|
|
253
|
+
from ipor_fusion import format_amount, parse_amount
|
|
254
|
+
|
|
255
|
+
assert format_amount(Amount(raw), Decimals(decimals)) == text
|
|
256
|
+
assert parse_amount(text, Decimals(decimals)) == raw
|
|
257
|
+
|
|
258
|
+
@pytest.mark.parametrize("raw", [-1, MAX_UINT256 + 1])
|
|
259
|
+
def test_format_amount_rejects_values_outside_uint256(self, raw):
|
|
260
|
+
from ipor_fusion import format_amount, format_shares
|
|
261
|
+
|
|
262
|
+
with pytest.raises(ValueError, match="within uint256"):
|
|
263
|
+
format_amount(Amount(raw), Decimals(6))
|
|
264
|
+
with pytest.raises(ValueError, match="within uint256"):
|
|
265
|
+
format_shares(Shares(raw), Decimals(6))
|
|
266
|
+
with pytest.raises(ValueError, match="0..255"):
|
|
267
|
+
format_amount(Amount(1), Decimals(256))
|
|
268
|
+
|
|
269
|
+
def test_shares_pair_mirrors_amounts(self):
|
|
270
|
+
from ipor_fusion import format_shares, parse_shares
|
|
271
|
+
|
|
272
|
+
assert parse_shares("2.5", Decimals(8)) == Shares(250_000_000)
|
|
273
|
+
assert format_shares(Shares(250_000_000), Decimals(8)) == "2.5"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/advanced_euler_v2_looping_arbitrum.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/external_state_margin_leg_base.py
RENAMED
|
File without changes
|
{ipor_fusion-4.0.0.dev255 → ipor_fusion-4.0.0.dev263}/examples/simple_aave_v3_supply_base.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|