feat(samples): add Tenzro DID-based settlement sample#256
feat(samples): add Tenzro DID-based settlement sample#256hilarl wants to merge 1 commit intogoogle-agentic-commerce:mainfrom
Conversation
Adds a runnable Python sample demonstrating the AP2 mandate chain (IntentMandate → CartMandate → PaymentMandate) running against a DID-based identity layer with on-chain delegation and a STARK settlement commitment. Uses TDIP/did:tenzro: as one concrete instance; the structure is identity-system-agnostic. Signed-off-by: Hilal Agil <hilaal@gmail.com> Co-Authored-By: Claude Opus 4 <noreply@anthropic.com> Signed-off-by: Hilal Agil <hilaal@gmail.com>
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive sample for DID-based settlement using the Tenzro Decentralized Identity Protocol (TDIP) and the AP2 SDK, featuring mandate chain construction, validation against four distinct ceilings, and a simulated ZK-proof settlement. The implementation includes a Tenzro JSON-RPC client and end-to-end tests. Feedback focuses on improving the ZK proof witness generation by utilizing the full hash for service proofs to maintain entropy and suggests replacing magic numbers in the RPC client with named constants for better maintainability.
| service_proof_hash = hashlib.sha256( | ||
| payment_mandate.model_dump_json().encode("utf-8") | ||
| ).digest() | ||
| service_proof_int = int.from_bytes(service_proof_hash[:4], "little") |
There was a problem hiding this comment.
Truncating the service_proof_hash to 4 bytes (32 bits) reduces the entropy of the witness field. Since the KoalaBear field prime is approximately 31 bits (
| service_proof_int = int.from_bytes(service_proof_hash[:4], "little") | |
| service_proof_int = int.from_bytes(service_proof_hash, "little") |
| if "error" in envelope and envelope["error"] is not None: | ||
| err = envelope["error"] | ||
| raise TenzroRpcError( | ||
| code=int(err.get("code", -32603)), |
feat(samples): add Tenzro DID-based settlement sample
Summary
Adds a new runnable Python sample under
code/samples/python/tenzro_did_settlement/that demonstrates the AP2mandate chain (
IntentMandate→CartMandate→PaymentMandate)running against a DID-based identity layer, with an on-chain
delegation primitive and a STARK-based settlement commitment.
The sample uses TDIP and
did:tenzro:as one concrete instance of a DID-based identity layer,but the structure is identity-system-agnostic — the chain-specific glue
is isolated in a single thin
tenzro_client.TenzroClientmodule so thesame sample skeleton works against
did:web,did:key,did:ion,did:eth, or any other W3C DID method whose chain exposes a comparabledelegation primitive and a settlement-proof primitive.
What's in the sample
The flow exercises all four nested validation ceilings that an AP2
mandate chain can be subject to in a DID-based deployment:
IntentMandateconstraints —max_amount, allowedmerchants, allowed SKUs, expiry. (Plain AP2 SDK semantics.)
CartMandateconsistency — total = sum of line items,parent intent matches, expiry. (Plain AP2 SDK semantics.)
DelegationScope::enforce_operation— a protocol-levelceiling set when the machine identity was registered
(
max_transaction_value,allowed_operations,allowed_payment_protocols,allowed_chains,time_bound).SpendingPolicy::check— an execution-levelceiling that the agent's runtime registry enforces (e.g. daily-spend
windows). Mutable; orthogonal to the protocol ceiling.
Settlement: a Plonky3 STARK over the
settlementAIR is generated viatenzro_createZkProof; its 32-byte SHA-256 commitment matches theon-chain
ZkCommitmentRegistryformat so the EVMZK_VERIFYprecompile becomes an O(1) HashSet lookup.
The
PaymentMandate.payment_method.supported_methodsistenzro:micropayment-channel, dispatching to a Tenzro per-messagebilling channel.
The sample also adds a one-paragraph subsection
"DID-based identity layer (example: TDIP)" to
docs/ap2/implementation_considerations.md(see the diff below).Why this fills a gap
The existing samples in
code/samples/python/scenarios/a2a/areexcellent demonstrations of card-based and x402-based flows, but they
use opaque identifiers for the user / agent / merchant parties. They do
not show what AP2 looks like when those identifiers are first-class
DIDs with on-chain delegation enforcement and verifiable-credential-
style scope binding.
AP2's mandate types are identity-system-agnostic — the principal,
agent, and merchant identifiers are opaque strings. This PR makes
that explicit by giving implementers a runnable, end-to-end example
of layering AP2 on top of a DID method.
What this PR does NOT touch
docs/ap2/specification.md,payment_mandate.md,flows.md, etc. are FIDO Alliance's responsibility now.code/sdk/python/ap2/is untouched. The sampleconsumes the SDK exactly as published.
requests,pydantic(a transitive dep ofap2already), and the test usesresponsesfor HTTP mocking. All deps are publicly available onPyPI; nothing private, nothing wallet-secret.
Test plan
The sample ships with
test_main.py, which runs the fullmain.run()flow end-to-end against a stub Tenzro JSON-RPC backendmocked with
responses:Expected: 5 tests pass.
test_intent_and_cart_build_and_round_trip— AP2 SDK objectsbuild correctly and round-trip into the Tenzro VDC envelope shape.
test_local_validation_passes_within_all_ceilings— all fourceilings green-light a within-budget cart.
test_local_validation_rejects_when_daily_window_exceeded— theSpendingPolicyceiling correctly fails when the daily window istoo small.
test_compute_zk_commitment_matches_expected_shape— the SHA-256commitment matches Tenzro's
compute_zk_commitmentshape.test_run_end_to_end_against_stub_rpc— the fullmain.run()flow drives the stub RPC through
resolve_did,ap2ValidateMandatePair, andcreateZkProof.test_run_offline_mode_skips_rpc—--offlineflag works.The sample also runs against the live testnet at
rpc.tenzro.networkwithout modification — the read-only RPCs (DID resolution, mandate
validation, ZK proof generation) require no funded keys; the channel
update is intentionally simulated because that step requires a
pre-opened, funded channel.
CLA acknowledgment
I have signed the Google CLA. This sample is a Tenzro-funded
contribution to the AP2 ecosystem; the copyright headers in
tenzro_client.pyandmain.pydeclare Apache-2.0 licensing,matching the rest of the repository.
AI assistance disclosure
Author: Hilal Agil <hilal@tenzro.com>, GitHub
@hilarl.
Parts of this contribution were AI-assisted via Claude Code. All
technical decisions — the choice to layer AP2 on top of TDIP, the
mapping from AP2's three mandate types onto Tenzro's IntentMandate /
CartMandate VDC envelope, the use of the
settlementPlonky3 AIR forthe commitment, the four-ceiling validation model — are human-authored
and consistent with Tenzro's production AP2 validator
(
tenzro_payments::ap2::MandateValidator::validate_with_delegation_and_policy).The drafting of boilerplate (docstrings, repetitive Pydantic model
construction, test scaffolding) was AI-assisted; every file was
reviewed and tested by the author before submission.
Checklist
code/samples/python/tenzro_did_settlement/only.requirements.txtpinned to specific versions.pytest test_main.py).docs/ap2/specification.md(FIDO scope).code/sdk/python/ap2/(SDK scope).docs/ap2/implementation_considerations.md(descriptive doc, notspec) — single paragraph cross-referencing the sample. Reviewers
who consider that file out of scope can drop it; the sample
stands on its own.
the existing repo convention.
rpc.tenzro.networktestnetend-to-end, no environment variables required.
DCO
Signed-off-by: Hilal Agil <hilal@tenzro.com>