Skip to content

Commit b6d8343

Browse files
committed
fix: Python facilitator e2e code
1 parent cae0546 commit b6d8343

File tree

5 files changed

+53
-14
lines changed

5 files changed

+53
-14
lines changed

e2e/clients/httpx/test.config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"svm"
88
],
99
"x402Versions": [
10+
1,
1011
2
1112
],
1213
"description": "Python httpx client with x402 v2 payment hooks",
@@ -20,4 +21,4 @@
2021
"SVM_PRIVATE_KEY"
2122
]
2223
}
23-
}
24+
}

e2e/clients/requests/test.config.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"svm"
88
],
99
"x402Versions": [
10+
1,
1011
2
1112
],
1213
"description": "Python requests client with x402 v2 HTTP adapter",
@@ -20,4 +21,4 @@
2021
"SVM_PRIVATE_KEY"
2122
]
2223
}
23-
}
24+
}

e2e/facilitators/python/main.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,7 @@ def _handle_after_verify(ctx: Any) -> None:
111111
.on_after_verify(lambda ctx: _handle_after_verify(ctx))
112112
.on_verify_failure(lambda ctx: print("Verify failure", ctx))
113113
.on_before_settle(lambda ctx: print("Before settle", ctx))
114-
.on_after_settle(
115-
lambda ctx: print(f"🎉 Payment settled: {ctx.result.transaction}")
116-
)
114+
.on_after_settle(lambda ctx: print(f"🎉 Payment settled: {ctx.result.transaction}"))
117115
.on_settle_failure(lambda ctx: print("Settle failure", ctx))
118116
)
119117

@@ -169,11 +167,13 @@ async def verify(request: VerifyRequest):
169167
VerifyResponse with isValid and payer (if valid) or invalidReason.
170168
"""
171169
try:
172-
from x402.schemas import PaymentRequirements, parse_payment_payload
170+
from x402.schemas import parse_payment_payload, parse_payment_requirements
173171

174-
# Parse payload (auto-detects V1/V2) and requirements
172+
# Parse payload (auto-detects V1/V2) and requirements (based on payload version)
175173
payload = parse_payment_payload(request.paymentPayload)
176-
requirements = PaymentRequirements.model_validate(request.paymentRequirements)
174+
requirements = parse_payment_requirements(
175+
payload.x402_version, request.paymentRequirements
176+
)
177177

178178
# Hooks will automatically:
179179
# - Track verified payment (on_after_verify)
@@ -203,11 +203,13 @@ async def settle(request: SettleRequest):
203203
SettleResponse with success, transaction, network, and payer.
204204
"""
205205
try:
206-
from x402.schemas import PaymentRequirements, parse_payment_payload
206+
from x402.schemas import parse_payment_payload, parse_payment_requirements
207207

208-
# Parse payload (auto-detects V1/V2) and requirements
208+
# Parse payload (auto-detects V1/V2) and requirements (based on payload version)
209209
payload = parse_payment_payload(request.paymentPayload)
210-
requirements = PaymentRequirements.model_validate(request.paymentRequirements)
210+
requirements = parse_payment_requirements(
211+
payload.x402_version, request.paymentRequirements
212+
)
211213

212214
# Hooks will automatically:
213215
# - Validate payment was verified (on_before_settle - will abort if not)
@@ -337,4 +339,3 @@ async def shutdown():
337339
print("Facilitator listening")
338340

339341
uvicorn.run(app, host="0.0.0.0", port=PORT, log_level="warning")
340-

python/x402/schemas/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
matches_network_pattern,
5555
parse_payment_payload,
5656
parse_payment_required,
57+
parse_payment_requirements,
5758
)
5859

5960
# Hook types
@@ -144,6 +145,7 @@
144145
"match_payload_to_requirements",
145146
"parse_payment_required",
146147
"parse_payment_payload",
148+
"parse_payment_requirements",
147149
"matches_network_pattern",
148150
"derive_network_pattern",
149151
"find_schemes_by_network",

python/x402/schemas/helpers.py

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
from typing import Any, TypeVar
55

66
from .base import Network
7-
from .payments import PaymentPayload, PaymentRequired
8-
from .v1 import PaymentPayloadV1, PaymentRequiredV1
7+
from .payments import PaymentPayload, PaymentRequired, PaymentRequirements
8+
from .v1 import PaymentPayloadV1, PaymentRequiredV1, PaymentRequirementsV1
99

1010

1111
def detect_version(data: bytes | dict[str, Any]) -> int:
@@ -159,6 +159,40 @@ def parse_payment_payload(
159159
return PaymentPayload.model_validate_json(json_str)
160160

161161

162+
def parse_payment_requirements(
163+
x402_version: int,
164+
data: bytes | dict[str, Any],
165+
) -> PaymentRequirements | PaymentRequirementsV1:
166+
"""Parse payment requirements based on protocol version.
167+
168+
Unlike parse_payment_payload which auto-detects version from the data,
169+
requirements don't contain x402Version - so the version must be provided
170+
from the corresponding payment payload.
171+
172+
Args:
173+
x402_version: Protocol version (1 or 2) from the payment payload.
174+
data: JSON bytes or parsed dict of payment requirements.
175+
176+
Returns:
177+
PaymentRequirements (V2) or PaymentRequirementsV1 (V1).
178+
179+
Raises:
180+
ValueError: If version is invalid.
181+
"""
182+
if x402_version not in (1, 2):
183+
raise ValueError(f"Invalid x402Version: {x402_version}")
184+
185+
if isinstance(data, bytes):
186+
json_str = data.decode("utf-8")
187+
else:
188+
json_str = json.dumps(data)
189+
190+
if x402_version == 1:
191+
return PaymentRequirementsV1.model_validate_json(json_str)
192+
else:
193+
return PaymentRequirements.model_validate_json(json_str)
194+
195+
162196
def matches_network_pattern(network: Network, pattern: Network) -> bool:
163197
"""Check if network matches a pattern (supports wildcards).
164198

0 commit comments

Comments
 (0)