iwa 0.0.13__tar.gz → 0.0.14__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.
- {iwa-0.0.13/src/iwa.egg-info → iwa-0.0.14}/PKG-INFO +1 -1
- {iwa-0.0.13 → iwa-0.0.14}/pyproject.toml +2 -2
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/interface.py +2 -1
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/contract.py +6 -1
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/utils.py +1 -1
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_staking_integration.py +5 -1
- {iwa-0.0.13 → iwa-0.0.14/src/iwa.egg-info}/PKG-INFO +1 -1
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/SOURCES.txt +1 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_chain.py +4 -4
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_contract.py +5 -4
- iwa-0.0.14/src/tests/test_rpc_rotation.py +287 -0
- {iwa-0.0.13 → iwa-0.0.14}/LICENSE +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/README.md +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/setup.cfg +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/__main__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/errors.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/manager.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/models.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/chain/rate_limiter.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/cli.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/constants.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/abis/erc20.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/abis/multisend.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/abis/multisend_call_only.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/erc20.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/contracts/multisend.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/db.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/ipfs.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/keys.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/mnemonic.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/models.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/monitor.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/plugins.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/pricing.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/secrets.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/account.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/balance.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/plugin.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/safe.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transaction.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/base.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/erc20.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/multisend.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/native.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/services/transfer/swap.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/tables.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/test.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/tests/test_wallet.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/types.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/ui.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/core/wallet.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow/quotes.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow/swap.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow/types.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/cow_utils.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/plugin.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/safe.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/tests/test_cow.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/gnosis/tests/test_safe.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/constants.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/activity_checker.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/mech.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/mech_marketplace.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/mech_new.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/service_manager.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/service_registry.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/service_registry_token_utility.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/staking.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/staking_token.json +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/activity_checker.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/base.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/mech.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/mech_marketplace.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/service.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/staking.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/importer.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/mech_reference.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/models.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/plugin.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/scripts/test_full_mech_flow.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/scripts/test_simple_lifecycle.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/base.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/drain.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/lifecycle.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/mech.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/service_manager/staking.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/conftest.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_importer.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_importer_error_handling.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_mech_contracts.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_contracts.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_integration.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_models.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_view.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_view_actions.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_olas_view_modals.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_plugin.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_plugin_full.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_lifecycle.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_errors.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_flows.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_mech.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_rewards.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_manager_validation.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_service_staking.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tests/test_staking_validation.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tui/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/tui/olas_view.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/check_profile.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/list_contracts.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/release.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/reset_env.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/reset_tenderly.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/restore_backup.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tools/wallet_check.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/app.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/modals/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/modals/base.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/rpc.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/screens/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/screens/wallets.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/tests/test_app.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/tests/test_rpc.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/tests/test_wallets_refactor.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/tests/test_widgets.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/widgets/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/widgets/base.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/tui/workers.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/dependencies.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/models.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/accounts.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/__init__.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/admin.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/funding.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/general.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/services.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/olas/staking.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/state.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/swap.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/routers/transactions.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/server.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/static/app.js +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/static/index.html +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/static/style.css +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/tests/test_web_endpoints.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/tests/test_web_olas.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/tests/test_web_swap.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa/web/tests/test_web_swap_coverage.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/dependency_links.txt +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/entry_points.txt +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/requires.txt +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/iwa.egg-info/top_level.txt +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_cow.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_safe.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_transaction_retry_logic.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_tui.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_wallets_screen.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/legacy_web.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_account_service.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_balance_service.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_chain_interface.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_chain_interface_coverage.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_cli.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_db.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_drain_coverage.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_erc20.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_gnosis_plugin.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_keys.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_legacy_wallet.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_main.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_migration.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_mnemonic.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_modals.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_models.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_monitor.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_multisend.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_plugin_service.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_pricing.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_rate_limiter.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_reset_tenderly.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_rpc_view.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_safe_coverage.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_safe_service.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_service_manager_integration.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_service_manager_structure.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_service_transaction.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_staking_router.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_staking_simple.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_tables.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transaction_service.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_multisend.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_native.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_security.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_structure.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_transfer_swap_unit.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_ui_coverage.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_utils.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tests/test_workers.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tools/create_and_stake_service.py +0 -0
- {iwa-0.0.13 → iwa-0.0.14}/src/tools/verify_drain.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "iwa"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.14"
|
|
4
4
|
description = "A secure, modular, and plugin-based framework for crypto agents and ops"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12,<4.0"
|
|
@@ -71,7 +71,7 @@ where = ["src"]
|
|
|
71
71
|
|
|
72
72
|
[tool.ruff]
|
|
73
73
|
line-length = 100
|
|
74
|
-
target-version = "0.0.
|
|
74
|
+
target-version = "0.0.14"
|
|
75
75
|
fix = true
|
|
76
76
|
|
|
77
77
|
[tool.ruff.lint]
|
|
@@ -379,7 +379,8 @@ class ChainInterface:
|
|
|
379
379
|
"""
|
|
380
380
|
try:
|
|
381
381
|
# Call decimals() directly without with_retry to avoid error logging
|
|
382
|
-
|
|
382
|
+
# Use _web3 directly to ensure current provider after RPC rotation
|
|
383
|
+
contract = self.web3._web3.eth.contract(
|
|
383
384
|
address=self.web3.to_checksum_address(address),
|
|
384
385
|
abi=[{"constant": True, "inputs": [], "name": "decimals", "outputs": [{"type": "uint8"}], "type": "function"}]
|
|
385
386
|
)
|
|
@@ -63,10 +63,15 @@ class ContractInstance:
|
|
|
63
63
|
|
|
64
64
|
This property ensures that after an RPC rotation, contract calls
|
|
65
65
|
use the updated provider instead of the original one.
|
|
66
|
+
|
|
67
|
+
Note: We use _web3 directly (not the RateLimitedWeb3 wrapper) to ensure
|
|
68
|
+
the contract is bound to the current provider. The wrapper's set_backend()
|
|
69
|
+
updates _web3, but contracts created via the wrapper may cache old providers.
|
|
66
70
|
"""
|
|
67
71
|
# Always create a fresh contract to use the current Web3 provider
|
|
68
72
|
# This is necessary because RPC rotation changes the underlying provider
|
|
69
|
-
|
|
73
|
+
# Access _web3 directly to ensure we get the current provider
|
|
74
|
+
return self.chain_interface.web3._web3.eth.contract(address=self.address, abi=self.abi)
|
|
70
75
|
|
|
71
76
|
def load_error_selectors(self) -> Dict[str, Any]:
|
|
72
77
|
"""Load error selectors from the contract ABI."""
|
|
@@ -87,7 +87,7 @@ def configure_logger():
|
|
|
87
87
|
|
|
88
88
|
def get_version(package_name: str) -> str:
|
|
89
89
|
"""Get package version."""
|
|
90
|
-
from importlib.metadata import
|
|
90
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
91
91
|
try:
|
|
92
92
|
return version(package_name)
|
|
93
93
|
except PackageNotFoundError:
|
|
@@ -194,9 +194,10 @@ def test_staking_contract(tmp_path): # noqa: C901
|
|
|
194
194
|
mock_chain = MagicMock()
|
|
195
195
|
mock_interfaces.return_value.get.return_value = mock_chain
|
|
196
196
|
|
|
197
|
-
# Mock web3
|
|
197
|
+
# Mock web3 - use _web3 since contract.py now accesses _web3 directly
|
|
198
198
|
mock_web3 = MagicMock()
|
|
199
199
|
mock_chain.web3 = mock_web3
|
|
200
|
+
mock_chain.web3._web3 = mock_web3 # For RPC rotation fix
|
|
200
201
|
|
|
201
202
|
# Mock contract factory
|
|
202
203
|
mock_contract = MagicMock()
|
|
@@ -252,6 +253,9 @@ def test_staking_contract(tmp_path): # noqa: C901
|
|
|
252
253
|
|
|
253
254
|
staking.ts_checkpoint = MagicMock(return_value=0)
|
|
254
255
|
|
|
256
|
+
# Mock get_required_requests to return an int (not MagicMock)
|
|
257
|
+
staking.get_required_requests = MagicMock(return_value=2)
|
|
258
|
+
|
|
255
259
|
# Trigger original_open hit
|
|
256
260
|
try:
|
|
257
261
|
test_file = tmp_path / "test_lookup.txt"
|
|
@@ -189,6 +189,7 @@ src/tests/test_plugin_service.py
|
|
|
189
189
|
src/tests/test_pricing.py
|
|
190
190
|
src/tests/test_rate_limiter.py
|
|
191
191
|
src/tests/test_reset_tenderly.py
|
|
192
|
+
src/tests/test_rpc_rotation.py
|
|
192
193
|
src/tests/test_rpc_view.py
|
|
193
194
|
src/tests/test_safe_coverage.py
|
|
194
195
|
src/tests/test_safe_service.py
|
|
@@ -340,10 +340,10 @@ def test_chain_interface_with_real_chains():
|
|
|
340
340
|
sym = interface.get_token_symbol(valid_addr_1)
|
|
341
341
|
assert sym == "SYM"
|
|
342
342
|
|
|
343
|
-
# get_token_decimals uses web3.eth.contract directly
|
|
343
|
+
# get_token_decimals uses web3._web3.eth.contract directly
|
|
344
344
|
mock_contract = MagicMock()
|
|
345
345
|
mock_contract.functions.decimals.return_value.call.return_value = 18
|
|
346
|
-
interface.web3.eth.contract.return_value = mock_contract
|
|
346
|
+
interface.web3._web3.eth.contract.return_value = mock_contract
|
|
347
347
|
|
|
348
348
|
dec = interface.get_token_decimals(valid_addr_1)
|
|
349
349
|
assert dec == 18
|
|
@@ -443,8 +443,8 @@ def test_get_token_decimals_fallback_on_error(mock_web3):
|
|
|
443
443
|
|
|
444
444
|
ci = ChainInterface(chain)
|
|
445
445
|
|
|
446
|
-
# get_token_decimals uses web3.eth.contract directly
|
|
447
|
-
ci.web3.eth.contract.side_effect = Exception("Contract not found")
|
|
446
|
+
# get_token_decimals uses web3._web3.eth.contract directly
|
|
447
|
+
ci.web3._web3.eth.contract.side_effect = Exception("Contract not found")
|
|
448
448
|
|
|
449
449
|
decimals = ci.get_token_decimals("0x1234567890123456789012345678901234567890")
|
|
450
450
|
|
|
@@ -11,7 +11,8 @@ from iwa.core.contracts.contract import ContractInstance
|
|
|
11
11
|
def mock_chain_interface():
|
|
12
12
|
with patch("iwa.core.contracts.contract.ChainInterfaces") as mock:
|
|
13
13
|
mock_ci = mock.return_value.get.return_value
|
|
14
|
-
|
|
14
|
+
# contract.py now uses web3._web3.eth.contract directly for RPC rotation compatibility
|
|
15
|
+
mock_ci.web3._web3.eth.contract.return_value = MagicMock()
|
|
15
16
|
yield mock_ci
|
|
16
17
|
|
|
17
18
|
|
|
@@ -226,7 +227,7 @@ def test_call_reevaluates_contract_on_retry(mock_chain_interface, mock_abi_file)
|
|
|
226
227
|
mock.functions.testFunc.return_value.call.return_value = "success"
|
|
227
228
|
return mock
|
|
228
229
|
|
|
229
|
-
mock_chain_interface.web3.eth.contract.side_effect = counting_contract_factory
|
|
230
|
+
mock_chain_interface.web3._web3.eth.contract.side_effect = counting_contract_factory
|
|
230
231
|
|
|
231
232
|
# Implement with_retry that actually retries on 429
|
|
232
233
|
def real_with_retry(fn, max_retries=6, operation_name="operation"):
|
|
@@ -274,7 +275,7 @@ def test_call_uses_fresh_provider_after_rotation(mock_chain_interface, mock_abi_
|
|
|
274
275
|
provider_versions.append(current_provider_version[0])
|
|
275
276
|
return mock
|
|
276
277
|
|
|
277
|
-
mock_chain_interface.web3.eth.contract.side_effect = mock_contract_factory
|
|
278
|
+
mock_chain_interface.web3._web3.eth.contract.side_effect = mock_contract_factory
|
|
278
279
|
|
|
279
280
|
# Simulate RPC rotation by incrementing provider version
|
|
280
281
|
def simulate_rotation():
|
|
@@ -335,7 +336,7 @@ def test_call_with_429_triggers_retry_with_new_contract(mock_chain_interface, mo
|
|
|
335
336
|
contract_call_count[0] += 1
|
|
336
337
|
return result
|
|
337
338
|
|
|
338
|
-
mock_chain_interface.web3.eth.contract.side_effect = mock_contract_factory
|
|
339
|
+
mock_chain_interface.web3._web3.eth.contract.side_effect = mock_contract_factory
|
|
339
340
|
|
|
340
341
|
# Implement with_retry that actually retries
|
|
341
342
|
def real_with_retry(fn, max_retries=6, operation_name="operation"):
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""Comprehensive RPC rotation tests.
|
|
2
|
+
|
|
3
|
+
These tests verify that RPC rotation works correctly when rate limit errors occur,
|
|
4
|
+
ensuring that after rotation, requests actually go to the new RPC.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from unittest.mock import MagicMock, PropertyMock, patch
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from iwa.core.chain import ChainInterface, SupportedChain
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class MockHTTPError(Exception):
|
|
15
|
+
"""Mock HTTP 429 error with URL info."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, url: str):
|
|
18
|
+
self.url = url
|
|
19
|
+
super().__init__(f"429 Client Error: Too Many Requests for url: {url}")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@pytest.fixture
|
|
23
|
+
def multi_rpc_chain():
|
|
24
|
+
"""Create a chain with multiple RPCs for testing rotation."""
|
|
25
|
+
chain = MagicMock(spec=SupportedChain)
|
|
26
|
+
chain.name = "TestChain"
|
|
27
|
+
chain.rpcs = [
|
|
28
|
+
"https://rpc1.example.com",
|
|
29
|
+
"https://rpc2.example.com",
|
|
30
|
+
"https://rpc3.example.com",
|
|
31
|
+
"https://rpc4.example.com",
|
|
32
|
+
"https://rpc5.example.com",
|
|
33
|
+
]
|
|
34
|
+
chain.chain_id = 1
|
|
35
|
+
chain.native_currency = "ETH"
|
|
36
|
+
chain.tokens = {}
|
|
37
|
+
type(chain).rpc = PropertyMock(return_value=chain.rpcs[0])
|
|
38
|
+
return chain
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@pytest.fixture
|
|
42
|
+
def mock_web3_factory():
|
|
43
|
+
"""Factory to create mock Web3 instances that track their RPC URL."""
|
|
44
|
+
|
|
45
|
+
def create_mock_web3(rpc_url: str):
|
|
46
|
+
mock = MagicMock()
|
|
47
|
+
mock.provider.endpoint_uri = rpc_url
|
|
48
|
+
mock.eth.block_number = 12345
|
|
49
|
+
return mock
|
|
50
|
+
|
|
51
|
+
return create_mock_web3
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_rpc_rotation_basic(multi_rpc_chain):
|
|
55
|
+
"""Test that RPC rotation cycles through all available RPCs."""
|
|
56
|
+
with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
|
|
57
|
+
ci = ChainInterface(multi_rpc_chain)
|
|
58
|
+
|
|
59
|
+
# Should start at index 0
|
|
60
|
+
assert ci._current_rpc_index == 0
|
|
61
|
+
|
|
62
|
+
# Rotate through all RPCs
|
|
63
|
+
for expected_index in [1, 2, 3, 4, 0, 1]: # Wraps around
|
|
64
|
+
result = ci.rotate_rpc()
|
|
65
|
+
assert result is True
|
|
66
|
+
assert ci._current_rpc_index == expected_index
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_rpc_rotation_updates_provider():
|
|
70
|
+
"""Test that after rotation, set_backend is called to update the provider.
|
|
71
|
+
|
|
72
|
+
The current implementation uses set_backend() to hot-swap the underlying
|
|
73
|
+
Web3 instance rather than creating a new RateLimitedWeb3 wrapper.
|
|
74
|
+
"""
|
|
75
|
+
chain = MagicMock(spec=SupportedChain)
|
|
76
|
+
chain.name = "TestChain"
|
|
77
|
+
chain.rpcs = ["https://rpc1.example.com", "https://rpc2.example.com"]
|
|
78
|
+
type(chain).rpc = PropertyMock(return_value=chain.rpcs[0])
|
|
79
|
+
|
|
80
|
+
set_backend_calls = []
|
|
81
|
+
|
|
82
|
+
class MockRateLimitedWeb3:
|
|
83
|
+
def __init__(self, w3, rl, ci):
|
|
84
|
+
self._web3 = w3
|
|
85
|
+
self.set_backend = MagicMock(side_effect=lambda new_w3: set_backend_calls.append(new_w3))
|
|
86
|
+
|
|
87
|
+
def __getattr__(self, name):
|
|
88
|
+
return getattr(self._web3, name)
|
|
89
|
+
|
|
90
|
+
with patch("iwa.core.chain.interface.Web3") as mock_web3_class:
|
|
91
|
+
with patch("iwa.core.chain.interface.RateLimitedWeb3", MockRateLimitedWeb3):
|
|
92
|
+
# Make Web3 return a mock with the correct provider URL
|
|
93
|
+
def create_web3_mock(provider):
|
|
94
|
+
mock = MagicMock()
|
|
95
|
+
mock.provider = provider
|
|
96
|
+
return mock
|
|
97
|
+
|
|
98
|
+
mock_web3_class.side_effect = create_web3_mock
|
|
99
|
+
mock_web3_class.HTTPProvider = lambda url, **kwargs: MagicMock(endpoint_uri=url)
|
|
100
|
+
|
|
101
|
+
ci = ChainInterface(chain)
|
|
102
|
+
|
|
103
|
+
# Initially no set_backend calls
|
|
104
|
+
assert len(set_backend_calls) == 0
|
|
105
|
+
|
|
106
|
+
# Rotate
|
|
107
|
+
ci.rotate_rpc()
|
|
108
|
+
|
|
109
|
+
# After rotation, set_backend should have been called
|
|
110
|
+
assert len(set_backend_calls) == 1
|
|
111
|
+
# And it should have been called with a new Web3 instance
|
|
112
|
+
assert set_backend_calls[0].provider.endpoint_uri == "https://rpc2.example.com"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_rate_limit_triggers_rotation(multi_rpc_chain):
|
|
116
|
+
"""Test that a 429 rate limit error triggers RPC rotation."""
|
|
117
|
+
with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
|
|
118
|
+
ci = ChainInterface(multi_rpc_chain)
|
|
119
|
+
|
|
120
|
+
initial_index = ci._current_rpc_index
|
|
121
|
+
assert initial_index == 0
|
|
122
|
+
|
|
123
|
+
# Simulate a rate limit error
|
|
124
|
+
error = MockHTTPError("https://rpc1.example.com")
|
|
125
|
+
result = ci._handle_rpc_error(error)
|
|
126
|
+
|
|
127
|
+
# Should have detected rate limit and rotated
|
|
128
|
+
assert result["is_rate_limit"] is True
|
|
129
|
+
assert result["rotated"] is True
|
|
130
|
+
assert result["should_retry"] is True
|
|
131
|
+
assert ci._current_rpc_index == 1
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def test_with_retry_rotates_on_rate_limit(multi_rpc_chain):
|
|
135
|
+
"""Test that with_retry properly rotates RPC on rate limit and succeeds on new RPC."""
|
|
136
|
+
with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
|
|
137
|
+
ci = ChainInterface(multi_rpc_chain)
|
|
138
|
+
|
|
139
|
+
call_count = 0
|
|
140
|
+
rpc_indices_seen = []
|
|
141
|
+
|
|
142
|
+
def flaky_operation():
|
|
143
|
+
nonlocal call_count
|
|
144
|
+
call_count += 1
|
|
145
|
+
rpc_indices_seen.append(ci._current_rpc_index)
|
|
146
|
+
|
|
147
|
+
# Fail on first RPC, succeed on second
|
|
148
|
+
if ci._current_rpc_index == 0:
|
|
149
|
+
raise MockHTTPError(ci.chain.rpcs[0])
|
|
150
|
+
return "success"
|
|
151
|
+
|
|
152
|
+
with patch("time.sleep"): # Skip actual delays
|
|
153
|
+
result = ci.with_retry(flaky_operation, operation_name="test_operation")
|
|
154
|
+
|
|
155
|
+
assert result == "success"
|
|
156
|
+
assert 0 in rpc_indices_seen # Started on RPC 0
|
|
157
|
+
assert 1 in rpc_indices_seen # Rotated to RPC 1
|
|
158
|
+
assert ci._current_rpc_index == 1 # Ended on RPC 1
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def test_with_retry_exhausts_all_rpcs_then_backs_off(multi_rpc_chain):
|
|
162
|
+
"""Test that when all RPCs fail, we trigger backoff."""
|
|
163
|
+
with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
|
|
164
|
+
ci = ChainInterface(multi_rpc_chain)
|
|
165
|
+
|
|
166
|
+
# All RPCs fail
|
|
167
|
+
def always_fail():
|
|
168
|
+
raise MockHTTPError(ci.chain.rpcs[ci._current_rpc_index])
|
|
169
|
+
|
|
170
|
+
with patch("time.sleep"):
|
|
171
|
+
with pytest.raises(MockHTTPError):
|
|
172
|
+
ci.with_retry(always_fail, max_retries=6, operation_name="doomed_operation")
|
|
173
|
+
|
|
174
|
+
# Should have rotated through multiple RPCs
|
|
175
|
+
assert ci._current_rpc_index > 0
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def test_rotation_applies_to_subsequent_calls():
|
|
179
|
+
"""Test that after rotation, subsequent method calls use the new RPC.
|
|
180
|
+
|
|
181
|
+
This is the critical test - verifying that the fix for the RPC rotation
|
|
182
|
+
bug actually works. After rotation, calls should go to the new RPC.
|
|
183
|
+
"""
|
|
184
|
+
chain = MagicMock(spec=SupportedChain)
|
|
185
|
+
chain.name = "TestChain"
|
|
186
|
+
chain.rpcs = ["https://rpc1.example.com", "https://rpc2.example.com"]
|
|
187
|
+
type(chain).rpc = PropertyMock(return_value=chain.rpcs[0])
|
|
188
|
+
|
|
189
|
+
with patch("iwa.core.chain.interface.Web3") as mock_web3_class:
|
|
190
|
+
# Track which provider is being used for each call
|
|
191
|
+
current_provider_url = ["https://rpc1.example.com"]
|
|
192
|
+
|
|
193
|
+
def create_web3(provider):
|
|
194
|
+
mock = MagicMock()
|
|
195
|
+
mock.provider = provider
|
|
196
|
+
|
|
197
|
+
# eth.get_balance should use the current provider
|
|
198
|
+
def mock_get_balance(addr):
|
|
199
|
+
return f"balance_from_{current_provider_url[0]}"
|
|
200
|
+
|
|
201
|
+
mock.eth.get_balance = mock_get_balance
|
|
202
|
+
mock.eth.block_number = 12345
|
|
203
|
+
return mock
|
|
204
|
+
|
|
205
|
+
def create_provider(url, **kwargs):
|
|
206
|
+
prov = MagicMock()
|
|
207
|
+
prov.endpoint_uri = url
|
|
208
|
+
current_provider_url[0] = url
|
|
209
|
+
return prov
|
|
210
|
+
|
|
211
|
+
mock_web3_class.side_effect = create_web3
|
|
212
|
+
mock_web3_class.HTTPProvider = create_provider
|
|
213
|
+
|
|
214
|
+
with patch(
|
|
215
|
+
"iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3
|
|
216
|
+
):
|
|
217
|
+
ci = ChainInterface(chain)
|
|
218
|
+
|
|
219
|
+
# First call uses RPC 1
|
|
220
|
+
result1 = ci.web3.eth.get_balance("0xtest")
|
|
221
|
+
assert "rpc1" in result1
|
|
222
|
+
|
|
223
|
+
# Rotate to RPC 2
|
|
224
|
+
ci.rotate_rpc()
|
|
225
|
+
|
|
226
|
+
# Second call should use RPC 2
|
|
227
|
+
result2 = ci.web3.eth.get_balance("0xtest")
|
|
228
|
+
assert "rpc2" in result2
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def test_contract_uses_current_provider_after_rotation():
|
|
232
|
+
"""Test that ContractInstance.contract property recreates contract each time.
|
|
233
|
+
|
|
234
|
+
This verifies the contract property doesn't cache and always
|
|
235
|
+
uses the current provider.
|
|
236
|
+
"""
|
|
237
|
+
# This is a simplified test that verifies the contract property
|
|
238
|
+
# creates a new contract each time it's accessed
|
|
239
|
+
from pathlib import Path
|
|
240
|
+
|
|
241
|
+
from iwa.core.contracts.contract import ContractInstance
|
|
242
|
+
|
|
243
|
+
# Mock a minimal chain interface
|
|
244
|
+
mock_web3 = MagicMock()
|
|
245
|
+
mock_web3._web3.eth.contract = MagicMock()
|
|
246
|
+
|
|
247
|
+
mock_chain_interface = MagicMock()
|
|
248
|
+
mock_chain_interface.web3 = mock_web3
|
|
249
|
+
|
|
250
|
+
# Create a ContractInstance with mocked dependencies
|
|
251
|
+
with patch("iwa.core.chain.ChainInterfaces") as mock_interfaces:
|
|
252
|
+
mock_interfaces.return_value.get.return_value = mock_chain_interface
|
|
253
|
+
|
|
254
|
+
# Mock the ABI loading
|
|
255
|
+
mock_abi = [{"type": "function", "name": "test", "inputs": [], "outputs": []}]
|
|
256
|
+
|
|
257
|
+
with patch("builtins.open", MagicMock()):
|
|
258
|
+
with patch("json.load", return_value=mock_abi):
|
|
259
|
+
# Need to mock abi_path for ContractInstance
|
|
260
|
+
with patch.object(ContractInstance, "abi_path", Path("/fake/path.json")):
|
|
261
|
+
with patch.object(ContractInstance, "load_error_selectors", return_value={}):
|
|
262
|
+
instance = ContractInstance.__new__(ContractInstance)
|
|
263
|
+
instance.address = "0x1234567890123456789012345678901234567890"
|
|
264
|
+
instance.abi = mock_abi
|
|
265
|
+
instance.chain_interface = mock_chain_interface
|
|
266
|
+
instance._contract_cache = None
|
|
267
|
+
instance.error_selectors = {}
|
|
268
|
+
|
|
269
|
+
# Access contract property twice
|
|
270
|
+
# The key test: verify it calls web3._web3.eth.contract each time
|
|
271
|
+
_ = instance.contract
|
|
272
|
+
_ = instance.contract
|
|
273
|
+
|
|
274
|
+
# Should have called contract() twice (no caching)
|
|
275
|
+
assert mock_web3._web3.eth.contract.call_count == 2
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def test_single_rpc_no_rotation(multi_rpc_chain):
|
|
279
|
+
"""Test that rotation returns False when there's only one RPC."""
|
|
280
|
+
multi_rpc_chain.rpcs = ["https://only-one.example.com"]
|
|
281
|
+
|
|
282
|
+
with patch("iwa.core.chain.interface.RateLimitedWeb3", side_effect=lambda w3, rl, ci: w3):
|
|
283
|
+
ci = ChainInterface(multi_rpc_chain)
|
|
284
|
+
|
|
285
|
+
result = ci.rotate_rpc()
|
|
286
|
+
assert result is False
|
|
287
|
+
assert ci._current_rpc_index == 0
|
|
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
|
|
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
|
|
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
|
{iwa-0.0.13 → iwa-0.0.14}/src/iwa/plugins/olas/contracts/abis/service_registry_token_utility.json
RENAMED
|
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
|