Files
hanzoai_agent/sdk/python/docs/web3-mpc-integration.md
Abhishek Krishna 38e687e42e feat(web3): MPC-signing integration for Web3 agents (closes #3)
Closes the two integration stubs and one broken import that block
hanzo_agents.extensions.web3 from doing real threshold-signed work:

1. New `mpc_client.py` — pydantic-typed `MpcClient` with `keygen`,
   `sign`, `verify`. HTTP-only against the `hanzoai/mpc` HTTP bridge
   (`POST /v1/{keygen,sign,verify}`). Configurable endpoint, timeout,
   retries, parties/threshold, optional bearer auth. Retries 5xx with
   exponential backoff; 4xx fail fast.

2. `web3_agent.verify_payment` — actually checks the chain. Pulls the
   tx receipt + tx, validates status==1, value >= expected (in wei),
   recipient == self.wallet.address, and >= configurable confirmations.
   Optional MPC cross-verification of the block-hash signature so a
   single party cannot spoof an ack. Mock-wallet path preserves legacy
   "trust the caller" behavior so existing tests keep passing.

3. `wallet.verify_signature` — uses `eth_account.Account.recover_message`
   with the EIP-191 prefix (matches `sign_message`). Returns False on
   malformed input rather than raising.

4. Fix `from .tee import …` → `from ..tee import …`. The `tee` package
   lives at `hanzo_agents.extensions.tee`, not under `extensions.web3`,
   so `from hanzo_agents.extensions.web3 import Web3Agent` currently
   raises `ModuleNotFoundError`.

Tests: `tests/test_web3_mpc_client.py` mocks `aiohttp.ClientSession`
and covers happy path for keygen/sign/verify, retry-on-5xx, fail-fast
on 4xx, hex validation, bearer-token header.

Docs: `docs/web3-mpc-integration.md` shows enable + wire protocol +
failure modes.

No new top-level deps. `aiohttp`, `pydantic`, `eth-account` are
already declared in `pyproject.toml`.

Total ~430 LOC across 1 new module, 2 patches, 1 test file, 1 doc.
2026-04-25 14:19:46 +05:30

2.8 KiB

Pointing a Web3 agent at a real MPC cluster

The Web3Agent ships with an optional integration to a hanzoai/mpc (or luxfi/mpc) threshold-signing cluster via an HTTP bridge. When enabled, payment-confirmation signatures are cross-verified against the cluster before the payment is recorded — so a single malicious party cannot spoof an ack.

Enable

from hanzo_agents.extensions.web3 import Web3Agent, Web3AgentConfig
from hanzo_agents.extensions.web3.mpc_client import MpcConfig

agent = Web3Agent(
    name="paid-worker",
    description="Does paid work, verifies via MPC",
    web3_config=Web3AgentConfig(
        wallet_enabled=True,
        wallet_config=...,                        # your WalletConfig
        mpc_enabled=True,
        mpc_config=MpcConfig(
            endpoint="https://mpc.example.com",   # HTTP bridge
            timeout_seconds=10.0,
            max_retries=3,
            parties=3,
            threshold=2,
            api_key="...",                        # if cluster requires bearer auth
        ),
        payment_min_confirmations=1,              # raise to 12+ for mainnet
    ),
)

mpc_enabled=False (the default) keeps the legacy chain-only verification path. mpc_config=None with mpc_enabled=True falls back to a localhost:8080 bridge — useful for development.

Wire protocol the bridge must speak

The client expects the HTTP bridge documented in hanzoai/mpc docs/BRIDGE-INTEGRATION.md:

Verb · path Request Response
POST /v1/keygen {"parties": n, "threshold": t} {"public_key": "<hex>", "key_id": "<id>"}
POST /v1/sign {"key_id": "<id>", "digest": "<hex>"} {"signature": "<hex>", "scheme": "ecdsa"}
POST /v1/verify {"signature": "<hex>", "digest": "<hex>", "public_key": "<hex>"} `{"valid": true

Failure modes

The client retries 5xx and network failures with exponential backoff (backoff_seconds * 2^attempt), respecting max_retries. 4xx responses are not retried — a malformed request will not be re-sent.

Web3Agent.verify_payment is conservative on MPC outage: if the bridge is unreachable but the chain-side checks pass (status, value, recipient, confirmations), the payment is still credited. Adjust by overriding verify_payment in a subclass if your threat model requires the MPC verify to be load-bearing.

Running the test suite

pytest sdk/python/tests/test_web3_mpc_client.py

The tests mock aiohttp.ClientSession, so no live bridge is needed.