Skip to content

Commit 6b87876

Browse files
authored
Merge pull request #3 from naory/feat/pypi-ready-and-rpc-helper
PyPI readiness, CI, and fetch_transaction_jsonrpc helper
2 parents 4afbe15 + 97dccde commit 6b87876

5 files changed

Lines changed: 135 additions & 10 deletions

File tree

.github/workflows/ci.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main, master]
6+
pull_request:
7+
branches: [main, master]
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
matrix:
14+
python-version: ["3.10", "3.11", "3.12"]
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- name: Checkout x402-xrpl (shared vectors)
19+
uses: actions/checkout@v4
20+
with:
21+
repository: naory/x402-xrpl
22+
path: x402-xrpl
23+
24+
- uses: actions/setup-python@v5
25+
with:
26+
python-version: ${{ matrix.python-version }}
27+
28+
- name: Install dependencies
29+
run: pip install -e ".[dev]"
30+
31+
- name: Run tests
32+
env:
33+
X402_TEST_VECTORS_PATH: ${{ github.workspace }}/x402-xrpl/conformance/test_vectors.json
34+
run: PYTHONPATH=src python -m pytest
35+
36+
- name: Ruff check
37+
run: ruff check src tests

README.md

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,6 @@ Strict **server-side settlement verifier** for **x402 v2 payments on XRPL**.
44

55
This package validates presigned XRPL `Payment` transactions and turns them into deterministic, replay-safe x402 settlement receipts for HTTP 402 flows.
66

7-
This repository is the Python port of the TypeScript XRPL adapter in
8-
[`naory/x402-xrpl`](https://github.com/naory/x402-xrpl). Both implementations
9-
share the same canonical conformance test vectors.
10-
117
Designed for backend services that require strong guarantees around:
128

139
- On-ledger settlement verification
@@ -54,9 +50,10 @@ Minimal by design:
5450
- `InMemoryReplayStore`
5551
- `SettlementVerificationError`
5652

57-
Optional helper:
53+
Optional helpers (stdlib-only; core stays dependency-free):
5854

59-
- `x402_xrpl_adapter.rpc.XrplJsonRpcClient`
55+
- `fetch_transaction_jsonrpc(network_url, tx_hash)` — minimal RPC fetch
56+
- `x402_xrpl_adapter.rpc.XrplJsonRpcClient` — wrapper for `verify_settlement` callback
6057

6158
---
6259

@@ -141,7 +138,18 @@ Second call with the same `paymentId` + `txHash` returns idempotent success.
141138

142139
## Optional XRPL JSON-RPC Helper
143140

144-
You can use the bundled minimal helper and pass it directly as the callback:
141+
Minimal stdlib-only helpers. Core verifier stays dependency-free.
142+
143+
**Function**`fetch_transaction_jsonrpc(network_url, tx_hash)`:
144+
145+
```python
146+
from x402_xrpl_adapter import fetch_transaction_jsonrpc
147+
148+
tx = fetch_transaction_jsonrpc("https://s.altnet.rippletest.net:51234", "ABCDEF123...")
149+
# returns dict or None
150+
```
151+
152+
**Class**`XrplJsonRpcClient` for use as `verify_settlement` callback:
145153

146154
```python
147155
from x402_xrpl_adapter.rpc import XrplJsonRpcClient

pyproject.toml

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,53 @@ build-backend = "hatchling.build"
55
[project]
66
name = "x402-xrpl-settlement-adapter-py"
77
version = "0.1.0"
8-
description = "Strict x402 v2 settlement verifier for XRPL (Python port)"
8+
description = "Server-side settlement verifier for x402 v2 on XRPL (XRP & issued tokens like RLUSD): strict Payment validation, memo binding, replay protection, no paths/partials."
99
readme = "README.md"
10-
requires-python = ">=3.9"
10+
requires-python = ">=3.10"
1111
license = { text = "MIT" }
1212
authors = [{ name = "Naor Yuval" }]
13+
keywords = [
14+
"x402",
15+
"x402-v2",
16+
"payment-protocol",
17+
"http-402",
18+
"payment-required",
19+
"xrpl",
20+
"xrp",
21+
"rlusd",
22+
"stablecoin",
23+
"iou",
24+
"issued-currency",
25+
"settlement",
26+
"settlement-verification",
27+
"verifier",
28+
"server",
29+
"backend",
30+
"middleware",
31+
"receipt",
32+
"replay-protection",
33+
"xaman",
34+
"xumm",
35+
]
36+
classifiers = [
37+
"Development Status :: 4 - Beta",
38+
"License :: OSI Approved :: MIT License",
39+
"Programming Language :: Python :: 3",
40+
"Programming Language :: Python :: 3 :: Only",
41+
"Programming Language :: Python :: 3.10",
42+
"Programming Language :: Python :: 3.11",
43+
"Programming Language :: Python :: 3.12",
44+
"Topic :: Office/Business :: Financial",
45+
"Intended Audience :: Developers",
46+
]
1347
dependencies = []
1448

49+
[project.urls]
50+
Homepage = "https://github.com/naory/x402-xrpl-python#readme"
51+
Repository = "https://github.com/naory/x402-xrpl-python"
52+
Documentation = "https://github.com/naory/x402-xrpl-python#readme"
53+
"Bug Tracker" = "https://github.com/naory/x402-xrpl-python/issues"
54+
1555
[project.optional-dependencies]
1656
dev = [
1757
"pytest>=8.2.0",
@@ -27,7 +67,7 @@ addopts = "-q"
2767

2868
[tool.ruff]
2969
line-length = 100
30-
target-version = "py39"
70+
target-version = "py310"
3171

3272
[tool.ruff.lint]
3373
select = ["E", "F", "I"]

src/x402_xrpl_adapter/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
create_challenge,
55
verify_settlement,
66
)
7+
from .rpc import fetch_transaction_jsonrpc
78

89
__all__ = [
910
"create_challenge",
1011
"verify_settlement",
1112
"SettlementVerificationError",
1213
"InMemoryReplayStore",
14+
"fetch_transaction_jsonrpc",
1315
]

src/x402_xrpl_adapter/rpc.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,46 @@
1+
"""Optional XRPL JSON-RPC helpers. Stdlib-only; core verifier stays dependency-free."""
2+
13
import json
24
from typing import Any, Dict, Optional
35
from urllib.request import Request, urlopen
46

57

8+
def fetch_transaction_jsonrpc(network_url: str, tx_hash: str) -> Optional[Dict[str, Any]]:
9+
"""
10+
Fetch a transaction from an XRPL node via JSON-RPC.
11+
12+
Args:
13+
network_url: XRPL node URL (e.g. https://s.altnet.rippletest.net:51234).
14+
tx_hash: Transaction hash (hex).
15+
16+
Returns:
17+
Transaction result dict, or None if not found or on error.
18+
"""
19+
payload = {
20+
"method": "tx",
21+
"params": [{"transaction": tx_hash, "binary": False}],
22+
}
23+
body = json.dumps(payload).encode("utf-8")
24+
request = Request(
25+
network_url,
26+
data=body,
27+
headers={"Content-Type": "application/json"},
28+
method="POST",
29+
)
30+
try:
31+
with urlopen(request, timeout=10) as response:
32+
raw = response.read().decode("utf-8")
33+
parsed = json.loads(raw)
34+
except Exception:
35+
return None
36+
result = parsed.get("result")
37+
if not isinstance(result, dict):
38+
return None
39+
if result.get("error") is not None:
40+
return None
41+
return result
42+
43+
644
class XrplJsonRpcClient:
745
"""Tiny optional helper for XRPL JSON-RPC tx lookup."""
846

0 commit comments

Comments
 (0)