From 9afd6db7d6aa64f970d2f80ef36d3e64f7a50806 Mon Sep 17 00:00:00 2001 From: Fsocietyhhh <1211904451@qq.com> Date: Sun, 5 Jul 2026 14:32:24 -0700 Subject: [PATCH] feat(x402): attach BlockRun builder-code service code to payments Tag every x402 payment this SDK signs with the ERC-8021 Schema 2 service code s: ["blockrun"] so BlockRun-originated traffic is attributed on-chain. Merged into builder-code.info.s inside create_payment_payload, preserving any app code (a) the server echoes back in its 402. Encoding into settlement calldata is handled by the CDP facilitator; the client only sets the JSON field, so no new dependency is required. Covers the EVM signing path. The Solana path delegates to the external x402 SDK and is tracked separately. Docs: https://docs.cdp.coinbase.com/x402/core-concepts/builder-codes --- blockrun_llm/x402.py | 26 +++++++++++++++++++++++++- tests/unit/test_x402.py | 25 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/blockrun_llm/x402.py b/blockrun_llm/x402.py index 36b32a8..4576519 100644 --- a/blockrun_llm/x402.py +++ b/blockrun_llm/x402.py @@ -23,6 +23,30 @@ USDC_BASE_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" +# BlockRun's x402 builder code — the ERC-8021 Schema 2 service code (`s`) that +# tags every payment this SDK signs as BlockRun-originated for on-chain +# attribution. See https://docs.cdp.coinbase.com/x402/core-concepts/builder-codes +BLOCKRUN_SERVICE_CODE = "blockrun" + + +def with_builder_code_service_code( + extensions: Optional[Dict[str, Any]], +) -> Dict[str, Any]: + """Merge BlockRun's service code (``s``) into the payload's ``builder-code`` + extension, preserving any app code (``a``) the server echoed back in its 402. + + The CDP facilitator reads ``builder-code.info.s`` and encodes it into the + settlement calldata suffix — no CBOR/encoding happens client-side. + """ + merged: Dict[str, Any] = dict(extensions or {}) + existing = dict(merged.get("builder-code") or {}) + info = dict(existing.get("info") or {}) + info["s"] = [BLOCKRUN_SERVICE_CODE] + existing["info"] = info + merged["builder-code"] = existing + return merged + + def get_chain_config(network: str) -> tuple[int, str]: """ Get chain ID and USDC contract address for a given network. @@ -174,7 +198,7 @@ def create_payment_payload( "nonce": nonce, }, }, - "extensions": extensions or {}, + "extensions": with_builder_code_service_code(extensions), } # Encode as base64 diff --git a/tests/unit/test_x402.py b/tests/unit/test_x402.py index 62ca893..7665c3d 100644 --- a/tests/unit/test_x402.py +++ b/tests/unit/test_x402.py @@ -72,6 +72,31 @@ def test_payload_includes_authorization(self): assert "validBefore" in auth assert "nonce" in auth + def test_payload_attaches_builder_code_service_code(self): + """Should tag every payment with the BlockRun service code (s).""" + payload = create_payment_payload( + account=TEST_ACCOUNT, + recipient=TEST_RECIPIENT, + amount="1000000", + ) + + decoded = json.loads(base64.b64decode(payload)) + assert decoded["extensions"]["builder-code"]["info"]["s"] == ["blockrun"] + + def test_payload_preserves_echoed_app_code(self): + """Should keep the server-echoed app code (a) when adding service code (s).""" + payload = create_payment_payload( + account=TEST_ACCOUNT, + recipient=TEST_RECIPIENT, + amount="1000000", + extensions={"builder-code": {"info": {"a": "blockrun"}}}, + ) + + decoded = json.loads(base64.b64decode(payload)) + info = decoded["extensions"]["builder-code"]["info"] + assert info["a"] == "blockrun" + assert info["s"] == ["blockrun"] + def test_payload_includes_resource_info(self): """Should include resource information.""" payload = create_payment_payload(