Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ e2e/servers/gin/server
e2e/servers/nethttp/nethttp
e2e/servers/mcp-go/mcp-go
e2e/servers/mcp-go/mcp-server
e2e/servers/nethttp/nethttp
e2e/legacy/servers/gin/gin

# Example build artifacts
Expand All @@ -41,3 +42,7 @@ TASK.md
.claude/
skills/
REVIEW_PROMPT.md
.omx/
.omc/
/demo/
/contracts/tvm/
30 changes: 27 additions & 3 deletions e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ pnpm test
```

Launches an interactive CLI where you can select:
- **Facilitators** - Payment verification/settlement services (Go, TypeScript)
- **Facilitators** - Payment verification/settlement services (Go, TypeScript, Python)
- **Servers** - Protected endpoints requiring payment (Express, Gin, Hono, Next.js, FastAPI, Flask, etc.)
- **Clients** - Payment-capable HTTP clients (axios, fetch, httpx, requests, etc.)
- **Extensions** - Additional features like Bazaar discovery
- **Protocols** - EVM, SVM, Aptos, and/or Hedera networks
- **Protocols** - EVM, SVM, Aptos, Hedera, Stellar, and/or TVM networks
- **Payment schemes** (when multiple apply) - `exact`, `upto`, or `batch-settlement`

Every valid combination of your selections will be tested. For example, selecting 2 facilitators, 3 servers, and 2 clients will generate and run all compatible test scenarios.
Expand Down Expand Up @@ -118,13 +118,15 @@ CLIENT_APTOS_PRIVATE_KEY=... # Aptos private key for client payments (hex
CLIENT_HEDERA_ACCOUNT_ID=0.0.... # Hedera account id for client payments
CLIENT_HEDERA_PRIVATE_KEY=0x... # Hedera ECDSA private key for client payments
CLIENT_STELLAR_PRIVATE_KEY=... # Stellar private key for client payments
CLIENT_TVM_PRIVATE_KEY=... # TVM private key for client payments

# Server payment addresses
SERVER_EVM_ADDRESS=0x... # Where servers receive EVM payments
SERVER_SVM_ADDRESS=... # Where servers receive Solana payments
SERVER_APTOS_ADDRESS=0x... # Where servers receive Aptos payments
SERVER_HEDERA_ADDRESS=0.0.... # Where servers receive Hedera payments
SERVER_STELLAR_ADDRESS=... # Where servers receive Stellar payments
SERVER_TVM_ADDRESS=... # Where servers receive TVM payments

# Facilitator wallets (⚠️ TEST WALLETS ONLY — used to fund/drain client between tests)
FACILITATOR_EVM_PRIVATE_KEY=0x... # EVM private key for facilitator
Expand All @@ -133,6 +135,22 @@ FACILITATOR_APTOS_PRIVATE_KEY=... # Aptos private key for facilitator (hex str
FACILITATOR_HEDERA_ACCOUNT_ID=0.0... # Hedera fee payer account id for facilitator
FACILITATOR_HEDERA_PRIVATE_KEY=0x... # Hedera ECDSA private key for facilitator
FACILITATOR_STELLAR_PRIVATE_KEY=... # Stellar private key for facilitator
FACILITATOR_TVM_PRIVATE_KEY=... # TVM private key for facilitator

# TVM support
TVM_PROVIDER=tonapi # Optional: toncenter (default) or tonapi
TONAPI_API_KEY=... # Required when TVM_PROVIDER=tonapi
TONAPI_BASE_URL=... # Optional custom TonAPI base URL
TONCENTER_API_KEY=... # Recommended when TVM_PROVIDER=toncenter
```

To run Python SDK TVM e2e scenarios through TonAPI instead of Toncenter:

```bash
cd e2e
TVM_PROVIDER=tonapi \
TONAPI_API_KEY=<tonapi-key> \
pnpm test --testnet --families=tvm --facilitators=python --clients=httpx,requests --servers=fastapi,flask --min -v
```

Optional environment variables (batch-settlement scheme):
Expand All @@ -154,6 +172,12 @@ You need **three separate Stellar accounts** for e2e tests (client, server, faci
3. Get testnet USDC from [Circle Faucet](https://faucet.circle.com/) (select Stellar network).

> **Note:** The facilitator account only needs XLM (step 1). Client and server accounts need all three steps.
##### TON testnet funding for TVM e2e and examples

- **Testnet TON**: use [@testgiver_ton_bot](https://t.me/testgiver_ton_bot) to fund the facilitator and payer wallets with TON for relay fees. The facilitator wallet must hold **at least 1.1 TON** before running tests.
- **Testnet USDT**: the payer wallet also needs testnet USDT. Open the [TON transfer link](https://app.tonkeeper.com/transfer/kQDNUDJC0iQvJoZp0ml-YteL1NtTXKphU03CTI5v4VtBhGYs?amount=49000000&bin=te6cckEBAQEAFgAAKClXdJkAAAAAAAAAAAAAAAAAmJaAhDUekg) or scan the QR code below to get them. The facilitator wallet only needs TON.
- **Note:** the facilitator uses a highload-wallet-v3 account, so the facilitator's wallet address differs from your W5 address — fund the highload-v3 address, not the W5 one derived from the same key.
<img width="228" height="228" alt="QR code for the testnet USDT transfer link" src="https://github.com/user-attachments/assets/da09ad03-388d-4960-88bf-afbacf4a7c65" />

## Example Session

Expand All @@ -167,7 +191,7 @@ $ pnpm test --min
✔ Select servers › express, hono, legacy-express
✔ Select clients › axios, fetch, httpx
✔ Select extensions › bazaar
✔ Select protocol families › EVM, SVM, Aptos, Hedera, Stellar
✔ Select protocol families › EVM, SVM, Aptos, Hedera, Stellar, TVM

📊 Coverage-Based Minimization
Total scenarios: 156
Expand Down
43 changes: 40 additions & 3 deletions e2e/clients/httpx/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@
from dotenv import load_dotenv
from eth_account import Account

logging.basicConfig(level=logging.INFO, format="%(name)s %(levelname)s: %(message)s", stream=__import__('sys').stderr)
logging.basicConfig(
level=logging.INFO,
format="%(name)s %(levelname)s: %(message)s",
stream=__import__("sys").stderr,
)
logging.getLogger("x402.signers").setLevel(logging.DEBUG)
logging.getLogger("x402.permit2").setLevel(logging.DEBUG)

Expand All @@ -19,6 +23,14 @@
from x402.mechanisms.evm.upto import UptoEvmClientScheme
from x402.mechanisms.svm import KeypairSigner
from x402.mechanisms.svm.exact import register_exact_svm_client
from x402.mechanisms.tvm import (
TVM_MAINNET,
TVM_PROVIDER_TONAPI,
TVM_TESTNET,
WalletV5R1Config,
WalletV5R1MnemonicSigner,
)
from x402.mechanisms.tvm.exact import ExactTvmClientScheme
import httpx

# Load environment variables
Expand All @@ -27,7 +39,14 @@
# Get environment variables
evm_private_key = os.getenv("EVM_PRIVATE_KEY")
svm_private_key = os.getenv("SVM_PRIVATE_KEY")
tvm_private_key = os.getenv("TVM_PRIVATE_KEY")
evm_rpc_url = os.getenv("EVM_RPC_URL", "https://sepolia.base.org")
tvm_provider = (os.getenv("TVM_PROVIDER") or "").strip().lower()
toncenter_api_key = os.getenv("TONCENTER_API_KEY")
toncenter_base_url = os.getenv("TONCENTER_BASE_URL")
tonapi_api_key = os.getenv("TONAPI_API_KEY")
tonapi_base_url = os.getenv("TONAPI_BASE_URL")
tvm_network = os.getenv("TVM_NETWORK", TVM_TESTNET)
base_url = os.getenv("RESOURCE_SERVER_URL")
endpoint_path = os.getenv("ENDPOINT_PATH")

Expand All @@ -36,10 +55,10 @@
print(json.dumps(error_result))
exit(1)

if not evm_private_key and not svm_private_key:
if not evm_private_key and not svm_private_key and not tvm_private_key:
error_result = {
"success": False,
"error": "At least one of EVM_PRIVATE_KEY or SVM_PRIVATE_KEY must be set",
"error": "At least one of EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, or TVM_PRIVATE_KEY must be set",
}
print(json.dumps(error_result))
exit(1)
Expand All @@ -61,6 +80,24 @@ async def main():
svm_signer = KeypairSigner.from_base58(svm_private_key)
register_exact_svm_client(client, svm_signer)

if tvm_private_key:
if tvm_network not in {TVM_TESTNET, TVM_MAINNET}:
raise ValueError(f"Unsupported TVM network: {tvm_network}")
tvm_config = WalletV5R1Config.from_private_key(tvm_network, tvm_private_key)
tvm_config.provider = tvm_provider or tvm_config.provider
tvm_config.api_key = (
tonapi_api_key if tvm_provider == TVM_PROVIDER_TONAPI else toncenter_api_key
)
tvm_config.provider_base_url = (
tonapi_base_url
if tvm_provider == TVM_PROVIDER_TONAPI
else toncenter_base_url
)
client.register(
tvm_network,
ExactTvmClientScheme(WalletV5R1MnemonicSigner(tvm_config)),
)

# Create httpx client with x402 payment transport and increased timeout
# Set timeout to 30 seconds to handle busy servers during test runs
timeout = httpx.Timeout(30.0, connect=10.0)
Expand Down
2 changes: 1 addition & 1 deletion e2e/clients/httpx/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Python httpx client for x402 e2e tests"
requires-python = ">=3.10"
dependencies = [
"python-dotenv>=1.0.0",
"x402[httpx,evm,svm,extensions]"
"x402[httpx,evm,svm,tvm,extensions]"
]

[build-system]
Expand Down
12 changes: 10 additions & 2 deletions e2e/clients/httpx/test.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"language": "python",
"protocolFamilies": [
"evm",
"svm"
"svm",
"tvm"
],
"x402Versions": [
1,
Expand Down Expand Up @@ -33,7 +34,14 @@
"optional": [
"EVM_PRIVATE_KEY",
"SVM_PRIVATE_KEY",
"EVM_RPC_URL"
"TVM_PRIVATE_KEY",
"EVM_RPC_URL",
"TVM_NETWORK",
"TVM_PROVIDER",
"TONCENTER_API_KEY",
"TONCENTER_BASE_URL",
"TONAPI_API_KEY",
"TONAPI_BASE_URL"
]
}
}
Loading
Loading