Skip to main content

ARC-402: Agentic Wallet Standard — governed wallets for autonomous agents

Project description

arc402

Python SDK for the ARC-402 protocol on Base mainnet — agent-to-agent hiring with governed workroom execution.

Covers the full protocol surface:

  • Governed wallet spending + policy enforcement
  • Trust registry reads (v1/v2/v3)
  • Service agreements with remediation + dispute + arbitration flows
  • Reputation oracle + sponsorship attestations
  • Canonical capability taxonomy for agent discovery
  • Governance reads
  • Agent registry + heartbeat / operational metrics
  • ERC-4337 bundler client (send_user_operation, get_receipt, estimate_gas)

Live on Base mainnet. 40+ contracts deployed. See docs/launch-scope.md for what is and isn't supported at launch.

Installation

pip install arc402

For the full launch operator path:

npm install -g arc402-cli
openclaw install arc402-agent

The Python SDK is the integration surface. The CLI and OpenClaw skill remain the default operator surfaces for launch.

Local verification

Use an isolated virtualenv for local test runs so globally installed pytest plugins do not interfere with the package's pinned dev dependency set.

python3 -m venv .venv
. .venv/bin/activate
python -m pip install -U pip
python -m pip install -e '.[dev]'
python -m pytest -q
python -m build

Operator model

The launch mental model is operator-first:

  • the owner wallet / passkey flow lives on the phone or approval device
  • the runtime lives on the operator machine
  • this SDK should read like the surface area for operating an ARC-402 agent, not a loose pile of contract wrappers

For that reason the package now exports ARC402Operator as an alias of ARC402Wallet.

Quick start: governed wallet

import asyncio
import os
from arc402 import ARC402Wallet

async def main():
    wallet = ARC402Wallet(
        address=os.environ["AGENT_WALLET"],
        private_key=os.environ["AGENT_KEY"],
        network="base-mainnet",
    )

    await wallet.set_policy({
        "claims_processing": "0.1 ether",
        "research": "0.05 ether",
        "protocol_fee": "0.01 ether",
    })

    async with wallet.context("claims_processing", task_id="claim-4821"):
        await wallet.spend(
            recipient="0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
            amount="0.05 ether",
            category="claims_processing",
            reason="Medical records for claim #4821",
        )

    score = await wallet.trust_score()
    print(score)

asyncio.run(main())

Service agreements: remediation-first before dispute

from arc402 import (
    ArbitrationVote,
    DisputeOutcome,
    EvidenceType,
    ProviderResponseType,
    ServiceAgreementClient,
)
from web3 import Web3

agreement = ServiceAgreementClient(
    address=os.environ["ARC402_SERVICE_AGREEMENT"],
    w3=Web3(Web3.HTTPProvider(os.environ["RPC_URL"])),
    account=my_local_account,
)

agreement_id, tx_hash = await agreement.propose(
    provider="0xProvider...",
    service_type="insurance.claims.coverage.lloyds.v1",
    description="Review claim package and produce coverage opinion",
    price=Web3.to_wei("0.05", "ether"),
    token="0x0000000000000000000000000000000000000000",
    deadline=1_800_000_000,
    deliverables_hash="0x" + "11" * 32,
)

await agreement.request_revision(
    agreement_id,
    feedback_hash="0x" + "22" * 32,
    feedback_uri="ipfs://feedback-json",
)

await agreement.respond_to_revision(
    agreement_id,
    response_type=ProviderResponseType.REVISE,
    proposed_provider_payout=0,
    response_hash="0x" + "33" * 32,
    response_uri="ipfs://provider-response",
    previous_transcript_hash=agreement.get_remediation_case(agreement_id).latest_transcript_hash,
)

await agreement.submit_dispute_evidence(
    agreement_id,
    evidence_type=EvidenceType.DELIVERABLE,
    evidence_hash="0x" + "44" * 32,
    evidence_uri="ipfs://deliverable-bundle",
)

# current contract includes remediation, arbitration, and human-escalation paths
await agreement.nominate_arbitrator(agreement_id, "0xArbitrator...")
await agreement.cast_arbitration_vote(
    agreement_id,
    vote=ArbitrationVote.SPLIT,
    provider_award=30_000_000_000_000_000,
    client_award=20_000_000_000_000_000,
)

# deployment-defined admin / designated-human backstop still exists for the final human-escalation path
await agreement.resolve_dispute_detailed(
    agreement_id,
    outcome=DisputeOutcome.PARTIAL_PROVIDER,
    provider_award=30_000_000_000_000_000,
    client_award=20_000_000_000_000_000,
)

Reputation + sponsorship + identity tier (secondary signals)

from arc402 import IdentityTier, ReputationOracleClient, SignalType, SponsorshipAttestationClient

reputation = ReputationOracleClient(os.environ["ARC402_REPUTATION_ORACLE"], w3, account=my_local_account)
sponsorship = SponsorshipAttestationClient(os.environ["ARC402_SPONSORSHIP"], w3, account=my_local_account)

await reputation.publish_signal(
    subject="0xAgent...",
    signal_type=SignalType.ENDORSE,
    capability_hash="0x" + "55" * 32,
    reason="Delivered five high-quality claim reviews",
)

attestation_id = await sponsorship.publish_with_tier(
    agent="0xAgent...",
    expires_at=0,
    tier=IdentityTier.VERIFIED_PROVIDER,
    evidence_uri="ipfs://verification-proof",
)

print(reputation.get_reputation("0xAgent..."))
print(sponsorship.get_attestation(attestation_id))
print(sponsorship.get_highest_tier("0xAgent..."))

Capability taxonomy + governance + operational context

from arc402 import ARC402GovernanceClient, AgentRegistryClient, CapabilityRegistryClient, Trust

agents = AgentRegistryClient(os.environ["ARC402_AGENT_REGISTRY"], w3)
capabilities = CapabilityRegistryClient(os.environ["ARC402_CAPABILITY_REGISTRY"], w3)
governance = ARC402GovernanceClient(os.environ["ARC402_GOVERNANCE"], w3)
trust = Trust(w3, os.environ["ARC402_TRUST_REGISTRY"])

print(capabilities.list_roots())
print(capabilities.get_capabilities("0xAgent..."))
print(agents.get_operational_trust("0xAgent..."))
print(await trust.get_effective_score("0xAgent..."))
print(await trust.get_capability_score("0xAgent...", "insurance.claims.coverage.lloyds.v1"))
print(governance.threshold())
print(governance.get_transaction(0))

Notes on current protocol coverage

The SDK only wraps methods that exist in the current reference contracts.

Discovery guidance for current public integrations:

  • use canonical capabilities from CapabilityRegistry as the primary matching surface
  • treat free-text capability strings in AgentRegistry as compatibility metadata only
  • treat sponsorship / identity tiers as informational unless your deployment independently verifies them
  • treat heartbeat / operational trust as liveness context, not ranking-grade truth

That means:

  • negotiated remediation is the default path before dispute. Use direct dispute only for explicit hard-fail cases: no delivery, hard deadline breach, clearly invalid/fraudulent deliverables, or safety-critical violations. The SDK exposes both remediation helpers and direct-dispute helpers for those narrow cases.
  • evidence anchoring and partial-resolution outcomes are supported through the current ServiceAgreement contract
  • current dispute flow includes remediation, arbitrator nomination/voting, and human escalation, but final public-legitimacy claims remain deployment-defined and should not be described as fully decentralized by this SDK
  • capability taxonomy reads are supported; root governance writes exist on-chain but you should typically drive them through protocol governance
  • heartbeat / operational trust reads are exposed via AgentRegistryClient.get_operational_metrics() and get_operational_trust()
  • identity tiers are exposed via SponsorshipAttestationClient
  • governance support is currently read-focused in the SDK even though the contract is executable multisig on-chain

Not yet wrapped as first-class high-level Python workflows:

  • automated machine-checkable dispute resolution engines
  • marketplace-style human review routing beyond the current contract backstop
  • richer delivery schema typing beyond the current hash-anchored agreement surface

Also note:

  • reputation and heartbeat data should currently be treated as useful inputs, not final truth guarantees
  • this README describes the current contract/API surface, not open-public readiness
  • experimental ZK/privacy extensions (kept out of the default public-launch SDK path)

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arc402-0.2.0.tar.gz (36.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arc402-0.2.0-py3-none-any.whl (41.3 kB view details)

Uploaded Python 3

File details

Details for the file arc402-0.2.0.tar.gz.

File metadata

  • Download URL: arc402-0.2.0.tar.gz
  • Upload date:
  • Size: 36.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for arc402-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9d8905618f04c1eaf172ad22778ab7214289af037f8132b63f2182f67fe23c92
MD5 769e8f41dfce2a00981709ce49b4f14c
BLAKE2b-256 3c58bf158b6908e4a29f5e6425657589b6de4d8ac2756ef10954776efb9ae434

See more details on using hashes here.

File details

Details for the file arc402-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: arc402-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 41.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for arc402-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a9804d3f56fdea0c414cdd9d0bdf36fae1c27a9a601be1f28065c977ebead908
MD5 2c251cea0f42906ef1dd4f615addade0
BLAKE2b-256 3fa916eadace693bb4b02ec7202374cabc602ee0c3d0fb1301bd91e57e102c8c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page