agirails 2.3.0__tar.gz → 2.3.1__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.
- {agirails-2.3.0 → agirails-2.3.1}/.gitignore +1 -0
- agirails-2.3.1/PKG-INFO +226 -0
- agirails-2.3.1/README.md +170 -0
- {agirails-2.3.0 → agirails-2.3.1}/pyproject.toml +1 -1
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/client.py +1 -1
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/config/networks.py +1 -4
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/errors/__init__.py +2 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/errors/network.py +33 -0
- agirails-2.3.1/src/agirails/protocol/base.py +171 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/escrow.py +14 -111
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/kernel.py +11 -107
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/nonce.py +16 -7
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/runtime/blockchain_runtime.py +50 -13
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/__init__.py +0 -5
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/circuit_breaker.py +10 -4
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/security.py +3 -1
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/semaphore.py +14 -5
- agirails-2.3.1/src/agirails/version.py +4 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/aa/dual_nonce_manager.py +8 -2
- {agirails-2.3.0 → agirails-2.3.1}/tests/benchmarks/test_performance.py +44 -34
- agirails-2.3.1/tests/test_errors/test_transient_rpc.py +35 -0
- agirails-2.3.1/tests/test_protocol/test_contract_base.py +223 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_protocol/test_networks.py +14 -15
- agirails-2.3.0/PKG-INFO +0 -675
- agirails-2.3.0/README.md +0 -619
- agirails-2.3.0/src/agirails/version.py +0 -4
- {agirails-2.3.0 → agirails-2.3.1}/.env.example +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/.github/workflows/test.yml +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/CHANGELOG.md +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/LICENSE +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/MIGRATION.md +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/abi/ACTPKernel.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/abi/ERC20.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/abi/EscrowVault.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/abis/actp_kernel.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/abis/agent_registry.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/abis/eas.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/abis/escrow_vault.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/abis/usdc.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/adapter_registry.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/adapter_router.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/base.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/basic.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/i_adapter.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/standard.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/types.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/adapters/x402_adapter.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/builders/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/builders/delivery_proof.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/builders/quote.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/balance.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/batch.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/config.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/deploy_check.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/deploy_env.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/diff.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/init.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/mint.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/pay.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/publish.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/pull.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/simulate.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/time.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/tx.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/commands/watch.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/main.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/utils/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/utils/client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/utils/output.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/cli/utils/validation.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/config/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/config/abis/AgentRegistry.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/config/agirailsmd.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/config/pending_publish.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/config/publish_pipeline.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/config/sync_operations.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/erc8004/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/erc8004/bridge.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/erc8004/reputation_reporter.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/errors/agent.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/errors/base.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/errors/mock.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/errors/storage.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/errors/transaction.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/errors/validation.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level0/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level0/directory.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level0/provide.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level0/provider.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level0/request.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level1/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level1/agent.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level1/config.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level1/job.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/level1/pricing.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/agent_registry.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/did.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/eas.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/events.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/messages.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/protocol/proofs.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/py.typed +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/runtime/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/runtime/base.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/runtime/mock_runtime.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/runtime/mock_state_manager.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/runtime/types.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/storage/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/storage/archive_bundle_builder.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/storage/arweave_client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/storage/filebase_client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/storage/types.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/types/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/types/did.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/types/erc8004.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/types/message.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/types/transaction.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/types/x402.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/canonical_json.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/helpers.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/logger.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/logging.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/nonce_tracker.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/received_nonce_tracker.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/retry.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/secure_nonce.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/used_attestation_tracker.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/utils/validation.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/aa/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/aa/bundler_client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/aa/constants.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/aa/paymaster_client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/aa/transaction_batcher.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/aa/user_op_builder.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/auto_wallet_provider.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/eoa_wallet_provider.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/src/agirails/wallet/keystore.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/benchmarks/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/conftest.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/fixtures/parity/canonical_json.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/fixtures/parity/delivery_proof.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/fixtures/parity/eip712.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/fixtures/parity/service_hash.json +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/integration/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/integration/test_blockchain_runtime.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/integration/test_eas.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_adapters/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_adapters/test_adapter_router.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_adapters/test_basic.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_adapters/test_standard.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_adapters/test_x402_adapter.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_builders/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_builders/test_delivery_proof.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_builders/test_quote.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_cli/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_cli/test_cli_original.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_cli/test_publish.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_cli_deploy/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_cli_deploy/test_deploy.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_config/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_config/test_agirailsmd.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_config/test_pending_publish.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_erc8004/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_erc8004/test_bridge.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_erc8004/test_reputation_reporter.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_errors/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_errors/test_agent.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_errors/test_base.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_errors/test_network.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_errors/test_transaction.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_errors/test_validation.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_level0/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_level0/test_directory.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_level0/test_provider.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_level0/test_request.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_level1/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_level1/test_agent_lifecycle.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_level1/test_config.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_level1/test_pricing.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_packaging/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_packaging/test_smoke.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_parity.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_properties/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_properties/test_state_machine.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_protocol/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_protocol/test_did.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_protocol/test_eas_verification.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_protocol/test_proofs.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_runtime/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_runtime/test_concurrent_file_locking.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_runtime/test_mock_runtime.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_runtime/test_mock_state_manager.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_security/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_security/test_security_audit.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_storage/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_storage/conftest.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_storage/test_archive_bundle_builder.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_storage/test_arweave_client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_storage/test_filebase_client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_storage/test_types.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_types/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_types/test_message.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_types/test_transaction.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_attestation_replay.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_circuit_breaker.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_helpers.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_helpers_extended.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_nonce_tracker.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_nonce_tracker_extended.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_received_nonce_tracker_extended.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_retry.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_secure_nonce_concurrency.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_security.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_security_extended.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_validation.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_utils/test_validation_extended.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_wallet/__init__.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_wallet/test_auto_wallet_provider.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_wallet/test_bundler_client.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_wallet/test_dual_nonce_manager.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_wallet/test_keystore.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_wallet/test_transaction_batcher.py +0 -0
- {agirails-2.3.0 → agirails-2.3.1}/tests/test_wallet/test_user_op_builder.py +0 -0
agirails-2.3.1/PKG-INFO
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agirails
|
|
3
|
+
Version: 2.3.1
|
|
4
|
+
Summary: AGIRAILS Python SDK - Agent Commerce Transaction Protocol
|
|
5
|
+
Project-URL: Homepage, https://agirails.io
|
|
6
|
+
Project-URL: Documentation, https://docs.agirails.io
|
|
7
|
+
Project-URL: Repository, https://github.com/agirails/sdk-python
|
|
8
|
+
Project-URL: Issues, https://github.com/agirails/sdk-python/issues
|
|
9
|
+
Author-email: AGIRAILS Team <developers@agirails.io>
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: actp,ai-agents,base,blockchain,escrow,ethereum,payments,web3
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Requires-Dist: aiofiles<25.0.0,>=24.0.0
|
|
26
|
+
Requires-Dist: eth-abi<6.0.0,>=5.0.0
|
|
27
|
+
Requires-Dist: eth-account<0.14.0,>=0.13.0
|
|
28
|
+
Requires-Dist: eth-utils<6.0.0,>=5.0.0
|
|
29
|
+
Requires-Dist: httpx<1.0.0,>=0.27.0
|
|
30
|
+
Requires-Dist: pydantic<3.0.0,>=2.6.0
|
|
31
|
+
Requires-Dist: python-dateutil<3.0.0,>=2.8.0
|
|
32
|
+
Requires-Dist: rich<14.0.0,>=13.0.0
|
|
33
|
+
Requires-Dist: typer<1.0.0,>=0.12.0
|
|
34
|
+
Requires-Dist: typing-extensions<5.0.0,>=4.0.0; python_version < '3.10'
|
|
35
|
+
Requires-Dist: web3<8.0.0,>=7.0.0
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: black>=24.0.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: hypothesis>=6.100.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: mypy>=1.11.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: pytest-benchmark>=4.0.0; extra == 'dev'
|
|
42
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
43
|
+
Requires-Dist: pytest-timeout>=2.3.0; extra == 'dev'
|
|
44
|
+
Requires-Dist: pytest-xdist>=3.5.0; extra == 'dev'
|
|
45
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
46
|
+
Requires-Dist: ruff>=0.6.0; extra == 'dev'
|
|
47
|
+
Requires-Dist: types-aiofiles>=24.0.0; extra == 'dev'
|
|
48
|
+
Requires-Dist: types-python-dateutil>=2.8.0; extra == 'dev'
|
|
49
|
+
Provides-Extra: mutation
|
|
50
|
+
Requires-Dist: mutmut>=2.4.0; extra == 'mutation'
|
|
51
|
+
Provides-Extra: security
|
|
52
|
+
Requires-Dist: bandit>=1.7.0; extra == 'security'
|
|
53
|
+
Requires-Dist: pip-audit>=2.7.0; extra == 'security'
|
|
54
|
+
Requires-Dist: safety>=3.0.0; extra == 'security'
|
|
55
|
+
Description-Content-Type: text/markdown
|
|
56
|
+
|
|
57
|
+
# AGIRAILS Python SDK
|
|
58
|
+
|
|
59
|
+
[](https://pypi.org/project/agirails/)
|
|
60
|
+
[](https://www.python.org/downloads/)
|
|
61
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
62
|
+
[]()
|
|
63
|
+
|
|
64
|
+
The official Python SDK for the **Agent Commerce Transaction Protocol (ACTP)** — enabling AI agents to transact with each other through blockchain-based escrow on Base L2.
|
|
65
|
+
|
|
66
|
+
**Full 1:1 parity with TypeScript SDK v2.5.0.**
|
|
67
|
+
|
|
68
|
+
## Install
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install agirails==2.3.0
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Features
|
|
75
|
+
|
|
76
|
+
- **Adapter Routing** — priority-based adapter selection (Standard, Basic, X402)
|
|
77
|
+
- **x402 Payments** — HTTP-based instant payments with relay fee splitting
|
|
78
|
+
- **ERC-8004 Identity** — on-chain agent identity resolution and reputation
|
|
79
|
+
- **Keystore Security (AIP-13)** — fail-closed private key policy, `ACTP_KEYSTORE_BASE64` for CI/CD
|
|
80
|
+
- **AGIRAILS.md Source of Truth** — parse, hash, publish, pull, diff agent configs
|
|
81
|
+
- **Smart Wallet (ERC-4337)** — batched transactions with paymaster gas sponsorship
|
|
82
|
+
- **Lazy Publish** — mainnet activation deferred to first real transaction
|
|
83
|
+
- **Three-tier API** — Basic, Standard, and Advanced levels
|
|
84
|
+
- **Mock Runtime** — full local testing without blockchain
|
|
85
|
+
- **CLI** — `actp pay`, `publish`, `pull`, `diff`, `deploy:env`, `deploy:check`
|
|
86
|
+
- **Async-first** — built on asyncio
|
|
87
|
+
- **1,738 tests passing**
|
|
88
|
+
|
|
89
|
+
## Quick Start
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
import asyncio
|
|
93
|
+
from agirails import ACTPClient
|
|
94
|
+
|
|
95
|
+
async def main():
|
|
96
|
+
client = await ACTPClient.create(mode="mock", requester_address="0x1234...")
|
|
97
|
+
|
|
98
|
+
# Adapter router auto-selects the best path
|
|
99
|
+
# EVM address → ACTP (StandardAdapter)
|
|
100
|
+
result = await client.pay({"to": "0xProvider...", "amount": "10.00"})
|
|
101
|
+
|
|
102
|
+
# HTTP URL → x402 instant payment
|
|
103
|
+
result = await client.pay({"to": "https://api.example.com/pay", "amount": "5.00"})
|
|
104
|
+
|
|
105
|
+
# Agent ID → ERC-8004 resolve → ACTP
|
|
106
|
+
result = await client.pay({"to": "12345", "amount": "10.00"})
|
|
107
|
+
|
|
108
|
+
print(f"Transaction: {result.tx_id}, State: {result.state}")
|
|
109
|
+
|
|
110
|
+
asyncio.run(main())
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Adapter Routing
|
|
114
|
+
|
|
115
|
+
Priority-based adapter selection matching TypeScript `AdapterRouter`:
|
|
116
|
+
|
|
117
|
+
| Adapter | Priority | Target | Use Case |
|
|
118
|
+
|---------|----------|--------|----------|
|
|
119
|
+
| **X402Adapter** | 70 | `https://...` URLs | Instant HTTP payments with relay fee splitting |
|
|
120
|
+
| **StandardAdapter** | 60 | `0x...` addresses | Full ACTP lifecycle with escrow |
|
|
121
|
+
| **BasicAdapter** | 50 | `0x...` addresses | Simple pay-and-forget (Smart Wallet batched) |
|
|
122
|
+
|
|
123
|
+
## Keystore & Deployment Security (AIP-13)
|
|
124
|
+
|
|
125
|
+
Fail-closed private key policy with network-aware enforcement:
|
|
126
|
+
|
|
127
|
+
| Network | `ACTP_PRIVATE_KEY` | Behavior |
|
|
128
|
+
|---------|-------------------|----------|
|
|
129
|
+
| mock | Allowed | Silent |
|
|
130
|
+
| testnet (base-sepolia) | Allowed | Warn once |
|
|
131
|
+
| mainnet (base-mainnet) | Blocked | Hard fail |
|
|
132
|
+
|
|
133
|
+
**Resolution order:** `ACTP_PRIVATE_KEY` → `ACTP_KEYSTORE_BASE64` + `ACTP_KEY_PASSWORD` → `.actp/keystore.json` → `None`
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Generate base64 keystore for CI/CD
|
|
137
|
+
actp deploy:env
|
|
138
|
+
|
|
139
|
+
# Scan repo for exposed secrets
|
|
140
|
+
actp deploy:check
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## AGIRAILS.md Config Management
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
actp publish --network base-sepolia # Hash + upload to IPFS + register on-chain
|
|
147
|
+
actp pull --network base-sepolia # Fetch config from chain
|
|
148
|
+
actp diff --network base-sepolia # Compare local vs on-chain
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Transaction Lifecycle
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
INITIATED → QUOTED → COMMITTED → IN_PROGRESS → DELIVERED → SETTLED
|
|
155
|
+
↘ ↘ ↘
|
|
156
|
+
CANCELLED CANCELLED DISPUTED → SETTLED
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## CLI
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Payments
|
|
163
|
+
actp pay <to> <amount> [--deadline TIME]
|
|
164
|
+
actp balance [ADDRESS]
|
|
165
|
+
|
|
166
|
+
# Transaction management
|
|
167
|
+
actp tx list [--state STATE]
|
|
168
|
+
actp tx status <tx_id>
|
|
169
|
+
actp tx deliver <tx_id>
|
|
170
|
+
actp tx settle <tx_id>
|
|
171
|
+
|
|
172
|
+
# Config sync
|
|
173
|
+
actp publish [path]
|
|
174
|
+
actp pull [path] [--network NETWORK]
|
|
175
|
+
actp diff [path] [--network NETWORK]
|
|
176
|
+
|
|
177
|
+
# Deployment security
|
|
178
|
+
actp deploy:env
|
|
179
|
+
actp deploy:check [path] [--fix]
|
|
180
|
+
|
|
181
|
+
# Mock mode
|
|
182
|
+
actp mint <address> <amount>
|
|
183
|
+
actp time advance <duration>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## SDK Parity
|
|
187
|
+
|
|
188
|
+
Full 1:1 parity with TypeScript SDK v2.5.0:
|
|
189
|
+
|
|
190
|
+
| Feature | Python | TypeScript |
|
|
191
|
+
|---------|--------|------------|
|
|
192
|
+
| Adapter Routing | AdapterRouter + 3 adapters | AdapterRouter + 3 adapters |
|
|
193
|
+
| x402 Payments | X402Adapter with relay | X402Adapter with relay |
|
|
194
|
+
| ERC-8004 Identity | ERC8004Bridge + ReputationReporter | ERC8004Bridge + ReputationReporter |
|
|
195
|
+
| Keystore AIP-13 | Full (30-min TTL cache) | Full (30-min TTL cache) |
|
|
196
|
+
| AGIRAILS.md SOT | parse, hash, publish, pull, diff | parse, hash, publish, pull, diff |
|
|
197
|
+
| Smart Wallet | ERC-4337 scaffolding | ERC-4337 full |
|
|
198
|
+
| Lazy Publish | pending-publish lifecycle | pending-publish lifecycle |
|
|
199
|
+
| CLI Commands | pay, publish, pull, diff, deploy:* | pay, publish, pull, diff, deploy:* |
|
|
200
|
+
| State Machine | 8 states, all transitions | 8 states, all transitions |
|
|
201
|
+
| Cross-SDK Tests | Shared test vectors | Shared test vectors |
|
|
202
|
+
|
|
203
|
+
## Testing
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
pytest # Run all 1,738 tests
|
|
207
|
+
pytest -v # Verbose output
|
|
208
|
+
pytest tests/test_adapters/ # Adapter tests only
|
|
209
|
+
pytest -k "test_pay" # Pattern match
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Requirements
|
|
213
|
+
|
|
214
|
+
- Python 3.9+
|
|
215
|
+
- Dependencies: web3, eth-account, pydantic, aiofiles, httpx, typer, rich
|
|
216
|
+
|
|
217
|
+
## Links
|
|
218
|
+
|
|
219
|
+
- [PyPI](https://pypi.org/project/agirails/)
|
|
220
|
+
- [Documentation](https://docs.agirails.io)
|
|
221
|
+
- [GitHub](https://github.com/agirails/sdk-python)
|
|
222
|
+
- [Discord](https://discord.gg/nuhCt75qe4)
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
Apache 2.0 — see [LICENSE](LICENSE) for details.
|
agirails-2.3.1/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# AGIRAILS Python SDK
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/agirails/)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
6
|
+
[]()
|
|
7
|
+
|
|
8
|
+
The official Python SDK for the **Agent Commerce Transaction Protocol (ACTP)** — enabling AI agents to transact with each other through blockchain-based escrow on Base L2.
|
|
9
|
+
|
|
10
|
+
**Full 1:1 parity with TypeScript SDK v2.5.0.**
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install agirails==2.3.0
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Features
|
|
19
|
+
|
|
20
|
+
- **Adapter Routing** — priority-based adapter selection (Standard, Basic, X402)
|
|
21
|
+
- **x402 Payments** — HTTP-based instant payments with relay fee splitting
|
|
22
|
+
- **ERC-8004 Identity** — on-chain agent identity resolution and reputation
|
|
23
|
+
- **Keystore Security (AIP-13)** — fail-closed private key policy, `ACTP_KEYSTORE_BASE64` for CI/CD
|
|
24
|
+
- **AGIRAILS.md Source of Truth** — parse, hash, publish, pull, diff agent configs
|
|
25
|
+
- **Smart Wallet (ERC-4337)** — batched transactions with paymaster gas sponsorship
|
|
26
|
+
- **Lazy Publish** — mainnet activation deferred to first real transaction
|
|
27
|
+
- **Three-tier API** — Basic, Standard, and Advanced levels
|
|
28
|
+
- **Mock Runtime** — full local testing without blockchain
|
|
29
|
+
- **CLI** — `actp pay`, `publish`, `pull`, `diff`, `deploy:env`, `deploy:check`
|
|
30
|
+
- **Async-first** — built on asyncio
|
|
31
|
+
- **1,738 tests passing**
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
import asyncio
|
|
37
|
+
from agirails import ACTPClient
|
|
38
|
+
|
|
39
|
+
async def main():
|
|
40
|
+
client = await ACTPClient.create(mode="mock", requester_address="0x1234...")
|
|
41
|
+
|
|
42
|
+
# Adapter router auto-selects the best path
|
|
43
|
+
# EVM address → ACTP (StandardAdapter)
|
|
44
|
+
result = await client.pay({"to": "0xProvider...", "amount": "10.00"})
|
|
45
|
+
|
|
46
|
+
# HTTP URL → x402 instant payment
|
|
47
|
+
result = await client.pay({"to": "https://api.example.com/pay", "amount": "5.00"})
|
|
48
|
+
|
|
49
|
+
# Agent ID → ERC-8004 resolve → ACTP
|
|
50
|
+
result = await client.pay({"to": "12345", "amount": "10.00"})
|
|
51
|
+
|
|
52
|
+
print(f"Transaction: {result.tx_id}, State: {result.state}")
|
|
53
|
+
|
|
54
|
+
asyncio.run(main())
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Adapter Routing
|
|
58
|
+
|
|
59
|
+
Priority-based adapter selection matching TypeScript `AdapterRouter`:
|
|
60
|
+
|
|
61
|
+
| Adapter | Priority | Target | Use Case |
|
|
62
|
+
|---------|----------|--------|----------|
|
|
63
|
+
| **X402Adapter** | 70 | `https://...` URLs | Instant HTTP payments with relay fee splitting |
|
|
64
|
+
| **StandardAdapter** | 60 | `0x...` addresses | Full ACTP lifecycle with escrow |
|
|
65
|
+
| **BasicAdapter** | 50 | `0x...` addresses | Simple pay-and-forget (Smart Wallet batched) |
|
|
66
|
+
|
|
67
|
+
## Keystore & Deployment Security (AIP-13)
|
|
68
|
+
|
|
69
|
+
Fail-closed private key policy with network-aware enforcement:
|
|
70
|
+
|
|
71
|
+
| Network | `ACTP_PRIVATE_KEY` | Behavior |
|
|
72
|
+
|---------|-------------------|----------|
|
|
73
|
+
| mock | Allowed | Silent |
|
|
74
|
+
| testnet (base-sepolia) | Allowed | Warn once |
|
|
75
|
+
| mainnet (base-mainnet) | Blocked | Hard fail |
|
|
76
|
+
|
|
77
|
+
**Resolution order:** `ACTP_PRIVATE_KEY` → `ACTP_KEYSTORE_BASE64` + `ACTP_KEY_PASSWORD` → `.actp/keystore.json` → `None`
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Generate base64 keystore for CI/CD
|
|
81
|
+
actp deploy:env
|
|
82
|
+
|
|
83
|
+
# Scan repo for exposed secrets
|
|
84
|
+
actp deploy:check
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## AGIRAILS.md Config Management
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
actp publish --network base-sepolia # Hash + upload to IPFS + register on-chain
|
|
91
|
+
actp pull --network base-sepolia # Fetch config from chain
|
|
92
|
+
actp diff --network base-sepolia # Compare local vs on-chain
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Transaction Lifecycle
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
INITIATED → QUOTED → COMMITTED → IN_PROGRESS → DELIVERED → SETTLED
|
|
99
|
+
↘ ↘ ↘
|
|
100
|
+
CANCELLED CANCELLED DISPUTED → SETTLED
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## CLI
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Payments
|
|
107
|
+
actp pay <to> <amount> [--deadline TIME]
|
|
108
|
+
actp balance [ADDRESS]
|
|
109
|
+
|
|
110
|
+
# Transaction management
|
|
111
|
+
actp tx list [--state STATE]
|
|
112
|
+
actp tx status <tx_id>
|
|
113
|
+
actp tx deliver <tx_id>
|
|
114
|
+
actp tx settle <tx_id>
|
|
115
|
+
|
|
116
|
+
# Config sync
|
|
117
|
+
actp publish [path]
|
|
118
|
+
actp pull [path] [--network NETWORK]
|
|
119
|
+
actp diff [path] [--network NETWORK]
|
|
120
|
+
|
|
121
|
+
# Deployment security
|
|
122
|
+
actp deploy:env
|
|
123
|
+
actp deploy:check [path] [--fix]
|
|
124
|
+
|
|
125
|
+
# Mock mode
|
|
126
|
+
actp mint <address> <amount>
|
|
127
|
+
actp time advance <duration>
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## SDK Parity
|
|
131
|
+
|
|
132
|
+
Full 1:1 parity with TypeScript SDK v2.5.0:
|
|
133
|
+
|
|
134
|
+
| Feature | Python | TypeScript |
|
|
135
|
+
|---------|--------|------------|
|
|
136
|
+
| Adapter Routing | AdapterRouter + 3 adapters | AdapterRouter + 3 adapters |
|
|
137
|
+
| x402 Payments | X402Adapter with relay | X402Adapter with relay |
|
|
138
|
+
| ERC-8004 Identity | ERC8004Bridge + ReputationReporter | ERC8004Bridge + ReputationReporter |
|
|
139
|
+
| Keystore AIP-13 | Full (30-min TTL cache) | Full (30-min TTL cache) |
|
|
140
|
+
| AGIRAILS.md SOT | parse, hash, publish, pull, diff | parse, hash, publish, pull, diff |
|
|
141
|
+
| Smart Wallet | ERC-4337 scaffolding | ERC-4337 full |
|
|
142
|
+
| Lazy Publish | pending-publish lifecycle | pending-publish lifecycle |
|
|
143
|
+
| CLI Commands | pay, publish, pull, diff, deploy:* | pay, publish, pull, diff, deploy:* |
|
|
144
|
+
| State Machine | 8 states, all transitions | 8 states, all transitions |
|
|
145
|
+
| Cross-SDK Tests | Shared test vectors | Shared test vectors |
|
|
146
|
+
|
|
147
|
+
## Testing
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
pytest # Run all 1,738 tests
|
|
151
|
+
pytest -v # Verbose output
|
|
152
|
+
pytest tests/test_adapters/ # Adapter tests only
|
|
153
|
+
pytest -k "test_pay" # Pattern match
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Requirements
|
|
157
|
+
|
|
158
|
+
- Python 3.9+
|
|
159
|
+
- Dependencies: web3, eth-account, pydantic, aiofiles, httpx, typer, rich
|
|
160
|
+
|
|
161
|
+
## Links
|
|
162
|
+
|
|
163
|
+
- [PyPI](https://pypi.org/project/agirails/)
|
|
164
|
+
- [Documentation](https://docs.agirails.io)
|
|
165
|
+
- [GitHub](https://github.com/agirails/sdk-python)
|
|
166
|
+
- [Discord](https://discord.gg/nuhCt75qe4)
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
Apache 2.0 — see [LICENSE](LICENSE) for details.
|
|
@@ -317,7 +317,7 @@ class ACTPClient:
|
|
|
317
317
|
)
|
|
318
318
|
|
|
319
319
|
# Map mode to network name
|
|
320
|
-
network_name = "base-sepolia" if config.mode == "testnet" else "base"
|
|
320
|
+
network_name = "base-sepolia" if config.mode == "testnet" else "base-mainnet"
|
|
321
321
|
|
|
322
322
|
# Create EAS helper if config provided or attestation required
|
|
323
323
|
eas_helper = None
|
|
@@ -152,10 +152,7 @@ BASE_MAINNET = NetworkConfig(
|
|
|
152
152
|
max_fee_per_gas=500_000_000, # 0.5 gwei
|
|
153
153
|
max_priority_fee_per_gas=100_000_000, # 0.1 gwei
|
|
154
154
|
),
|
|
155
|
-
#
|
|
156
|
-
# This limits exposure in case of undiscovered vulnerabilities.
|
|
157
|
-
# Will be removed/increased after formal security audit.
|
|
158
|
-
max_transaction_amount=1000,
|
|
155
|
+
# Security audit passed February 2026 — no findings. No transaction limit.
|
|
159
156
|
)
|
|
160
157
|
|
|
161
158
|
|
|
@@ -37,6 +37,7 @@ from agirails.errors.validation import (
|
|
|
37
37
|
)
|
|
38
38
|
from agirails.errors.network import (
|
|
39
39
|
NetworkError,
|
|
40
|
+
TransientRPCError,
|
|
40
41
|
TransactionRevertedError,
|
|
41
42
|
SignatureVerificationError,
|
|
42
43
|
)
|
|
@@ -89,6 +90,7 @@ __all__ = [
|
|
|
89
90
|
"InvalidAmountError",
|
|
90
91
|
# Network
|
|
91
92
|
"NetworkError",
|
|
93
|
+
"TransientRPCError",
|
|
92
94
|
"TransactionRevertedError",
|
|
93
95
|
"SignatureVerificationError",
|
|
94
96
|
# Storage
|
|
@@ -95,6 +95,39 @@ class TransactionRevertedError(ACTPError):
|
|
|
95
95
|
self.block_number = block_number
|
|
96
96
|
|
|
97
97
|
|
|
98
|
+
class TransientRPCError(NetworkError):
|
|
99
|
+
"""
|
|
100
|
+
Raised for transient RPC/network failures that are safe to retry.
|
|
101
|
+
|
|
102
|
+
Distinguishes retry-able failures (connection drops, rate limits,
|
|
103
|
+
timeouts) from permanent failures (contract reverts, invalid state).
|
|
104
|
+
|
|
105
|
+
BlockchainRuntime._rate_limited_call() retries on this class only.
|
|
106
|
+
|
|
107
|
+
Example:
|
|
108
|
+
>>> raise TransientRPCError("Rate limit exceeded", cause=original_error)
|
|
109
|
+
"""
|
|
110
|
+
|
|
111
|
+
def __init__(
|
|
112
|
+
self,
|
|
113
|
+
message: str,
|
|
114
|
+
*,
|
|
115
|
+
endpoint: Optional[str] = None,
|
|
116
|
+
cause: Optional[Exception] = None,
|
|
117
|
+
details: Optional[Dict[str, Any]] = None,
|
|
118
|
+
) -> None:
|
|
119
|
+
details = details or {}
|
|
120
|
+
if cause is not None:
|
|
121
|
+
details["cause"] = type(cause).__name__
|
|
122
|
+
super().__init__(
|
|
123
|
+
message,
|
|
124
|
+
endpoint=endpoint,
|
|
125
|
+
details=details,
|
|
126
|
+
)
|
|
127
|
+
self.code = "TRANSIENT_RPC_ERROR"
|
|
128
|
+
self.cause = cause
|
|
129
|
+
|
|
130
|
+
|
|
98
131
|
class SignatureVerificationError(ACTPError):
|
|
99
132
|
"""
|
|
100
133
|
Raised when a cryptographic signature verification fails.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ContractBase: shared infrastructure for ACTPKernel and EscrowVault.
|
|
3
|
+
|
|
4
|
+
Eliminates the verbatim duplication of _sign_and_send, _build_tx_params,
|
|
5
|
+
_to_bytes32, and _to_receipt that existed in both contract wrappers.
|
|
6
|
+
|
|
7
|
+
NonceManager integration is optional:
|
|
8
|
+
- When nonce_manager is provided: get_nonce() / confirm_nonce() / release_nonce()
|
|
9
|
+
are called automatically inside _build_tx_params() and _sign_and_send().
|
|
10
|
+
- When None: falls back to w3.eth.get_transaction_count("pending") — same
|
|
11
|
+
behavior as pre-refactor, backward compat preserved.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
from typing import Any, Dict, Optional
|
|
18
|
+
|
|
19
|
+
from eth_account.signers.local import LocalAccount
|
|
20
|
+
from web3 import AsyncWeb3
|
|
21
|
+
from web3.contract import AsyncContract
|
|
22
|
+
from web3.types import TxReceipt
|
|
23
|
+
|
|
24
|
+
from agirails.errors.transaction import TransactionError
|
|
25
|
+
from agirails.protocol.nonce import NonceManager
|
|
26
|
+
from agirails.types.transaction import TransactionReceipt
|
|
27
|
+
|
|
28
|
+
# Security Note (M-3): Default timeout for transaction receipts (5 minutes)
|
|
29
|
+
DEFAULT_TX_WAIT_TIMEOUT = 300.0
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ContractBase:
|
|
33
|
+
"""
|
|
34
|
+
Abstract base for ACTPKernel and EscrowVault contract wrappers.
|
|
35
|
+
|
|
36
|
+
Owns the transaction lifecycle: build params -> sign -> send -> wait -> receipt.
|
|
37
|
+
Integrates NonceManager when provided, falls back to RPC nonce otherwise.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
contract: AsyncContract,
|
|
43
|
+
account: LocalAccount,
|
|
44
|
+
w3: AsyncWeb3,
|
|
45
|
+
chain_id: int,
|
|
46
|
+
*,
|
|
47
|
+
nonce_manager: Optional[NonceManager] = None,
|
|
48
|
+
) -> None:
|
|
49
|
+
self.contract = contract
|
|
50
|
+
self.account = account
|
|
51
|
+
self.w3 = w3
|
|
52
|
+
self.chain_id = chain_id
|
|
53
|
+
self._nonce_manager = nonce_manager
|
|
54
|
+
|
|
55
|
+
async def _build_tx_params(
|
|
56
|
+
self,
|
|
57
|
+
gas_limit: int,
|
|
58
|
+
max_fee_per_gas: Optional[int] = None,
|
|
59
|
+
max_priority_fee_per_gas: Optional[int] = None,
|
|
60
|
+
) -> Dict[str, Any]:
|
|
61
|
+
"""Build EIP-1559 transaction parameters."""
|
|
62
|
+
# Use NonceManager when available; else ask chain directly
|
|
63
|
+
if self._nonce_manager is not None:
|
|
64
|
+
nonce = await self._nonce_manager.get_nonce()
|
|
65
|
+
else:
|
|
66
|
+
# Legacy path: fetch nonce from RPC including unconfirmed transactions
|
|
67
|
+
nonce = await self.w3.eth.get_transaction_count(
|
|
68
|
+
self.account.address, "pending"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Get gas prices if not provided
|
|
72
|
+
if max_fee_per_gas is None or max_priority_fee_per_gas is None:
|
|
73
|
+
block = await self.w3.eth.get_block("latest")
|
|
74
|
+
base_fee = block.get("baseFeePerGas", 1_000_000_000) # 1 gwei fallback
|
|
75
|
+
|
|
76
|
+
if max_priority_fee_per_gas is None:
|
|
77
|
+
max_priority_fee_per_gas = 1_000_000_000 # 1 gwei
|
|
78
|
+
|
|
79
|
+
if max_fee_per_gas is None:
|
|
80
|
+
# 2x base fee + priority fee
|
|
81
|
+
max_fee_per_gas = (base_fee * 2) + max_priority_fee_per_gas
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
"from": self.account.address,
|
|
85
|
+
"nonce": nonce,
|
|
86
|
+
"gas": gas_limit,
|
|
87
|
+
"maxFeePerGas": max_fee_per_gas,
|
|
88
|
+
"maxPriorityFeePerGas": max_priority_fee_per_gas,
|
|
89
|
+
"chainId": self.chain_id,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async def _sign_and_send(
|
|
93
|
+
self,
|
|
94
|
+
tx: Dict[str, Any],
|
|
95
|
+
timeout: float = DEFAULT_TX_WAIT_TIMEOUT,
|
|
96
|
+
) -> TxReceipt:
|
|
97
|
+
"""
|
|
98
|
+
Sign and broadcast a transaction, wait for receipt.
|
|
99
|
+
|
|
100
|
+
Nonce lifecycle:
|
|
101
|
+
- Pre-broadcast failure -> release_nonce (nonce never hit the chain)
|
|
102
|
+
- Post-broadcast timeout -> confirm_nonce (tx is in mempool, nonce consumed)
|
|
103
|
+
- Reverted tx (status=0) -> confirm_nonce (revert still consumed nonce)
|
|
104
|
+
- Success (status=1) -> confirm_nonce
|
|
105
|
+
|
|
106
|
+
Security Note (M-3): Uses timeout to prevent indefinite hangs.
|
|
107
|
+
"""
|
|
108
|
+
nonce: Optional[int] = tx.get("nonce")
|
|
109
|
+
|
|
110
|
+
signed_tx = self.w3.eth.account.sign_transaction(tx, self.account.key)
|
|
111
|
+
try:
|
|
112
|
+
tx_hash = await self.w3.eth.send_raw_transaction(
|
|
113
|
+
signed_tx.raw_transaction
|
|
114
|
+
)
|
|
115
|
+
except Exception:
|
|
116
|
+
# Broadcast failed — release nonce so it can be reused
|
|
117
|
+
if self._nonce_manager is not None and nonce is not None:
|
|
118
|
+
self._nonce_manager.release_nonce(nonce)
|
|
119
|
+
raise
|
|
120
|
+
|
|
121
|
+
# Transaction was broadcast — nonce is consumed regardless of outcome
|
|
122
|
+
try:
|
|
123
|
+
receipt = await asyncio.wait_for(
|
|
124
|
+
self.w3.eth.wait_for_transaction_receipt(tx_hash),
|
|
125
|
+
timeout=timeout,
|
|
126
|
+
)
|
|
127
|
+
except asyncio.TimeoutError:
|
|
128
|
+
# TX is in mempool — nonce is consumed
|
|
129
|
+
if self._nonce_manager is not None and nonce is not None:
|
|
130
|
+
self._nonce_manager.confirm_nonce(nonce)
|
|
131
|
+
raise TransactionError(
|
|
132
|
+
f"Transaction {tx_hash.hex()} timed out after {timeout}s. "
|
|
133
|
+
"Check network congestion and gas settings.",
|
|
134
|
+
tx_id=tx_hash.hex(),
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
# Confirm nonce whether tx succeeded or reverted (nonce was used on-chain)
|
|
138
|
+
if self._nonce_manager is not None and nonce is not None:
|
|
139
|
+
self._nonce_manager.confirm_nonce(nonce)
|
|
140
|
+
|
|
141
|
+
if receipt["status"] != 1:
|
|
142
|
+
raise TransactionError(
|
|
143
|
+
f"Transaction failed: {tx_hash.hex()}",
|
|
144
|
+
tx_id=tx_hash.hex(),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return receipt
|
|
148
|
+
|
|
149
|
+
def _to_bytes32(self, value: str) -> bytes:
|
|
150
|
+
"""Convert hex string to bytes32."""
|
|
151
|
+
if value.startswith("0x"):
|
|
152
|
+
value = value[2:]
|
|
153
|
+
# Pad to 32 bytes if needed
|
|
154
|
+
value = value.zfill(64)
|
|
155
|
+
return bytes.fromhex(value)
|
|
156
|
+
|
|
157
|
+
def _to_receipt(self, receipt: TxReceipt) -> TransactionReceipt:
|
|
158
|
+
"""Convert web3 receipt to TransactionReceipt."""
|
|
159
|
+
return TransactionReceipt(
|
|
160
|
+
transaction_hash=receipt["transactionHash"].hex()
|
|
161
|
+
if isinstance(receipt["transactionHash"], bytes)
|
|
162
|
+
else receipt["transactionHash"],
|
|
163
|
+
block_number=receipt["blockNumber"],
|
|
164
|
+
block_hash=receipt["blockHash"].hex()
|
|
165
|
+
if isinstance(receipt["blockHash"], bytes)
|
|
166
|
+
else receipt["blockHash"],
|
|
167
|
+
gas_used=receipt["gasUsed"],
|
|
168
|
+
effective_gas_price=receipt.get("effectiveGasPrice", 0),
|
|
169
|
+
status=receipt["status"],
|
|
170
|
+
logs=[dict(log) for log in receipt.get("logs", [])],
|
|
171
|
+
)
|