uvd-x402-sdk 0.5.2__py3-none-any.whl → 0.5.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
uvd_x402_sdk/__init__.py CHANGED
@@ -32,16 +32,17 @@ Example usage:
32
32
  def protected_endpoint():
33
33
  return {"message": "Payment verified!"}
34
34
 
35
- Supported Networks (16 total):
35
+ Supported Networks (18 total):
36
36
  - EVM (10): Base, Ethereum, Polygon, Arbitrum, Optimism, Avalanche, Celo,
37
37
  HyperEVM, Unichain, Monad
38
38
  - SVM (2): Solana, Fogo
39
39
  - NEAR (1): NEAR Protocol
40
40
  - Stellar (1): Stellar
41
41
  - Algorand (2): Algorand mainnet, Algorand testnet
42
+ - Sui (2): Sui mainnet, Sui testnet
42
43
  """
43
44
 
44
- __version__ = "0.5.2"
45
+ __version__ = "0.5.4"
45
46
  __author__ = "Ultravioleta DAO"
46
47
 
47
48
  from uvd_x402_sdk.client import X402Client
@@ -128,6 +129,8 @@ from uvd_x402_sdk.facilitator import (
128
129
  NEAR_FEE_PAYER_TESTNET,
129
130
  STELLAR_FEE_PAYER_MAINNET,
130
131
  STELLAR_FEE_PAYER_TESTNET,
132
+ SUI_FEE_PAYER_MAINNET,
133
+ SUI_FEE_PAYER_TESTNET,
131
134
  # EVM facilitator addresses (for reference)
132
135
  EVM_FACILITATOR_MAINNET,
133
136
  EVM_FACILITATOR_TESTNET,
@@ -224,6 +227,8 @@ __all__ = [
224
227
  "NEAR_FEE_PAYER_TESTNET",
225
228
  "STELLAR_FEE_PAYER_MAINNET",
226
229
  "STELLAR_FEE_PAYER_TESTNET",
230
+ "SUI_FEE_PAYER_MAINNET",
231
+ "SUI_FEE_PAYER_TESTNET",
227
232
  "EVM_FACILITATOR_MAINNET",
228
233
  "EVM_FACILITATOR_TESTNET",
229
234
  "get_fee_payer",
@@ -58,6 +58,10 @@ NEAR_FEE_PAYER_TESTNET = "uvd-facilitator.testnet"
58
58
  STELLAR_FEE_PAYER_MAINNET = "GCHPGXJT2WFFRFCA5TV4G4E3PMMXLNIDUH27PKDYA4QJ2XGYZWGFZNHB"
59
59
  STELLAR_FEE_PAYER_TESTNET = "GBBFZMLUJEZVI32EN4XA2KPP445XIBTMTRBLYWFIL556RDTHS2OWFQ2Z"
60
60
 
61
+ # Sui fee payer addresses (sponsor wallets)
62
+ SUI_FEE_PAYER_MAINNET = "0xe7bbf2b13f7d72714760aa16e024fa1b35a978793f9893d0568a4fbf356a764a"
63
+ SUI_FEE_PAYER_TESTNET = "0xabbd16a2fab2a502c9cfe835195a6fc7d70bfc27cffb40b8b286b52a97006e67"
64
+
61
65
 
62
66
  # =============================================================================
63
67
  # EVM Facilitator Addresses (for reference - EVM uses EIP-3009, no fee payer needed)
@@ -95,6 +99,10 @@ _FEE_PAYER_BY_NETWORK: Dict[str, str] = {
95
99
  "stellar": STELLAR_FEE_PAYER_MAINNET,
96
100
  "stellar-mainnet": STELLAR_FEE_PAYER_MAINNET,
97
101
  "stellar-testnet": STELLAR_FEE_PAYER_TESTNET,
102
+ # Sui
103
+ "sui": SUI_FEE_PAYER_MAINNET,
104
+ "sui-mainnet": SUI_FEE_PAYER_MAINNET,
105
+ "sui-testnet": SUI_FEE_PAYER_TESTNET,
98
106
  }
99
107
 
100
108
  # CAIP-2 format mappings (x402 v2)
@@ -114,6 +122,9 @@ _FEE_PAYER_BY_CAIP2: Dict[str, str] = {
114
122
  # Stellar
115
123
  "stellar:pubnet": STELLAR_FEE_PAYER_MAINNET,
116
124
  "stellar:testnet": STELLAR_FEE_PAYER_TESTNET,
125
+ # Sui
126
+ "sui:mainnet": SUI_FEE_PAYER_MAINNET,
127
+ "sui:testnet": SUI_FEE_PAYER_TESTNET,
117
128
  }
118
129
 
119
130
 
@@ -48,7 +48,7 @@ from uvd_x402_sdk.networks.base import (
48
48
  )
49
49
 
50
50
  # Import all default network configurations
51
- from uvd_x402_sdk.networks import evm, solana, near, stellar, algorand
51
+ from uvd_x402_sdk.networks import evm, solana, near, stellar, algorand, sui
52
52
 
53
53
  __all__ = [
54
54
  # Core
@@ -57,6 +57,7 @@ class NetworkType(Enum):
57
57
  - NEAR: NEP-366 SignedDelegateAction (meta-transaction)
58
58
  - STELLAR: Soroban Authorization Entry XDR
59
59
  - ALGORAND: ASA (Algorand Standard Assets) transfer via signed transaction
60
+ - SUI: Sui sponsored transactions (Move-based programmable transactions)
60
61
 
61
62
  Note: SOLANA is deprecated, use SVM instead for Solana-compatible chains.
62
63
  """
@@ -67,12 +68,18 @@ class NetworkType(Enum):
67
68
  NEAR = "near"
68
69
  STELLAR = "stellar"
69
70
  ALGORAND = "algorand" # Algorand ASA transfers
71
+ SUI = "sui" # Sui Move VM chains (sponsored transactions)
70
72
 
71
73
  @classmethod
72
74
  def is_svm(cls, network_type: "NetworkType") -> bool:
73
75
  """Check if network type is SVM-compatible (Solana, Fogo, etc.)."""
74
76
  return network_type in (cls.SVM, cls.SOLANA)
75
77
 
78
+ @classmethod
79
+ def is_sui(cls, network_type: "NetworkType") -> bool:
80
+ """Check if network type is Sui-based."""
81
+ return network_type == cls.SUI
82
+
76
83
 
77
84
  @dataclass
78
85
  class NetworkConfig:
@@ -372,6 +379,7 @@ _CAIP2_NAMESPACE_MAP = {
372
379
  "near": NetworkType.NEAR,
373
380
  "stellar": NetworkType.STELLAR,
374
381
  "algorand": NetworkType.ALGORAND,
382
+ "sui": NetworkType.SUI,
375
383
  }
376
384
 
377
385
  # Network name to CAIP-2 format
@@ -397,6 +405,9 @@ _NETWORK_TO_CAIP2 = {
397
405
  # Algorand
398
406
  "algorand": "algorand:mainnet",
399
407
  "algorand-testnet": "algorand:testnet",
408
+ # Sui
409
+ "sui": "sui:mainnet",
410
+ "sui-testnet": "sui:testnet",
400
411
  }
401
412
 
402
413
  # CAIP-2 to network name mapping (reverse of above)
@@ -455,6 +466,11 @@ def parse_caip2_network(caip2_id: str) -> Optional[str]:
455
466
  return "algorand"
456
467
  if reference == "testnet":
457
468
  return "algorand-testnet"
469
+ if namespace == "sui":
470
+ if reference == "mainnet":
471
+ return "sui"
472
+ if reference == "testnet":
473
+ return "sui-testnet"
458
474
 
459
475
  return None
460
476
 
@@ -0,0 +1,387 @@
1
+ """
2
+ Sui network configurations.
3
+
4
+ This module supports Sui blockchain for x402 payments using sponsored transactions:
5
+ - Sui (mainnet)
6
+ - Sui Testnet
7
+
8
+ Supported Tokens:
9
+ - USDC: Native Sui USDC
10
+
11
+ All Sui chains use the same payment flow:
12
+ 1. User creates a programmable transaction for token transfer
13
+ 2. User signs the transaction
14
+ 3. Transaction is sent to the facilitator with the user's signature
15
+ 4. Facilitator sponsors the transaction (pays gas in SUI)
16
+ 5. Facilitator adds sponsor signature and submits to Sui network
17
+
18
+ Transaction Structure:
19
+ - Programmable Transaction Block (PTB) for USDC transfer
20
+ - TransferObjects or SplitCoins + TransferObjects commands
21
+ - Facilitator is gas sponsor (user pays ZERO SUI)
22
+
23
+ Key differences from other chains:
24
+ - Uses Move-based programmable transactions
25
+ - BCS (Binary Canonical Serialization) encoding
26
+ - 66-character addresses (0x + 64 hex)
27
+ - Coin types in format: package::module::type
28
+ """
29
+
30
+ import base64
31
+ from typing import Dict, Any, Optional
32
+
33
+ from uvd_x402_sdk.networks.base import (
34
+ NetworkConfig,
35
+ NetworkType,
36
+ TokenConfig,
37
+ register_network,
38
+ )
39
+
40
+ # Sui fee payer addresses (facilitator wallets)
41
+ try:
42
+ from uvd_x402_sdk.facilitator import (
43
+ SUI_FEE_PAYER_MAINNET,
44
+ SUI_FEE_PAYER_TESTNET,
45
+ get_fee_payer,
46
+ )
47
+ except ImportError:
48
+ # Fallback if facilitator module not loaded yet
49
+ SUI_FEE_PAYER_MAINNET = "0xe7bbf2b13f7d72714760aa16e024fa1b35a978793f9893d0568a4fbf356a764a"
50
+ SUI_FEE_PAYER_TESTNET = "0xabbd16a2fab2a502c9cfe835195a6fc7d70bfc27cffb40b8b286b52a97006e67"
51
+ get_fee_payer = None # type: ignore
52
+
53
+
54
+ # =============================================================================
55
+ # Sui Networks Configuration
56
+ # =============================================================================
57
+
58
+ # USDC coin types on Sui
59
+ SUI_USDC_COIN_TYPE_MAINNET = "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
60
+ SUI_USDC_COIN_TYPE_TESTNET = "0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC"
61
+
62
+ # Sui Mainnet
63
+ SUI = NetworkConfig(
64
+ name="sui",
65
+ display_name="Sui",
66
+ network_type=NetworkType.SUI,
67
+ chain_id=0, # Non-EVM, no chain ID
68
+ usdc_address=SUI_USDC_COIN_TYPE_MAINNET,
69
+ usdc_decimals=6,
70
+ usdc_domain_name="", # Not applicable for Sui
71
+ usdc_domain_version="",
72
+ rpc_url="https://fullnode.mainnet.sui.io:443",
73
+ enabled=True,
74
+ tokens={
75
+ "usdc": TokenConfig(
76
+ address=SUI_USDC_COIN_TYPE_MAINNET,
77
+ decimals=6,
78
+ name="", # Not applicable for Sui
79
+ version="",
80
+ ),
81
+ },
82
+ extra_config={
83
+ # Coin type for USDC (package::module::type format)
84
+ "usdc_coin_type": SUI_USDC_COIN_TYPE_MAINNET,
85
+ # Fee payer (facilitator) address
86
+ "fee_payer": SUI_FEE_PAYER_MAINNET,
87
+ # Block explorer
88
+ "explorer_url": "https://suiscan.xyz",
89
+ # Network identifier
90
+ "sui_network": "mainnet",
91
+ # Gas budget (in MIST, 1 SUI = 1e9 MIST)
92
+ "default_gas_budget": 10_000_000, # 0.01 SUI
93
+ },
94
+ )
95
+
96
+ # Sui Testnet
97
+ SUI_TESTNET = NetworkConfig(
98
+ name="sui-testnet",
99
+ display_name="Sui Testnet",
100
+ network_type=NetworkType.SUI,
101
+ chain_id=0, # Non-EVM, no chain ID
102
+ usdc_address=SUI_USDC_COIN_TYPE_TESTNET,
103
+ usdc_decimals=6,
104
+ usdc_domain_name="", # Not applicable for Sui
105
+ usdc_domain_version="",
106
+ rpc_url="https://fullnode.testnet.sui.io:443",
107
+ enabled=True,
108
+ tokens={
109
+ "usdc": TokenConfig(
110
+ address=SUI_USDC_COIN_TYPE_TESTNET,
111
+ decimals=6,
112
+ name="", # Not applicable for Sui
113
+ version="",
114
+ ),
115
+ },
116
+ extra_config={
117
+ # Coin type for USDC (package::module::type format)
118
+ "usdc_coin_type": SUI_USDC_COIN_TYPE_TESTNET,
119
+ # Fee payer (facilitator) address
120
+ "fee_payer": SUI_FEE_PAYER_TESTNET,
121
+ # Block explorer
122
+ "explorer_url": "https://suiscan.xyz/testnet",
123
+ # Network identifier
124
+ "sui_network": "testnet",
125
+ # Gas budget (in MIST, 1 SUI = 1e9 MIST)
126
+ "default_gas_budget": 10_000_000, # 0.01 SUI
127
+ },
128
+ )
129
+
130
+ # Register Sui networks
131
+ register_network(SUI)
132
+ register_network(SUI_TESTNET)
133
+
134
+
135
+ # =============================================================================
136
+ # Sui-specific utilities
137
+ # =============================================================================
138
+
139
+
140
+ def is_sui_network(network_name: str) -> bool:
141
+ """
142
+ Check if a network is Sui-based.
143
+
144
+ Args:
145
+ network_name: Network name to check
146
+
147
+ Returns:
148
+ True if network uses Sui
149
+ """
150
+ from uvd_x402_sdk.networks.base import get_network, NetworkType
151
+
152
+ network = get_network(network_name)
153
+ if not network:
154
+ return False
155
+ return NetworkType.is_sui(network.network_type)
156
+
157
+
158
+ def get_sui_networks() -> list:
159
+ """
160
+ Get all registered Sui networks.
161
+
162
+ Returns:
163
+ List of Sui NetworkConfig instances
164
+ """
165
+ from uvd_x402_sdk.networks.base import list_networks, NetworkType
166
+
167
+ return [
168
+ n for n in list_networks(enabled_only=True)
169
+ if NetworkType.is_sui(n.network_type)
170
+ ]
171
+
172
+
173
+ def is_valid_sui_address(address: str) -> bool:
174
+ """
175
+ Validate a Sui address format.
176
+
177
+ Sui addresses are 66 characters: 0x + 64 hex characters.
178
+
179
+ Args:
180
+ address: Address to validate
181
+
182
+ Returns:
183
+ True if valid Sui address
184
+ """
185
+ if not address or not isinstance(address, str):
186
+ return False
187
+
188
+ # Sui addresses start with 0x and have 64 hex characters after
189
+ if not address.startswith("0x"):
190
+ return False
191
+
192
+ hex_part = address[2:]
193
+ if len(hex_part) != 64:
194
+ return False
195
+
196
+ # Validate hex characters
197
+ try:
198
+ int(hex_part, 16)
199
+ return True
200
+ except ValueError:
201
+ return False
202
+
203
+
204
+ def is_valid_sui_coin_type(coin_type: str) -> bool:
205
+ """
206
+ Validate a Sui coin type format.
207
+
208
+ Sui coin types follow format: package_address::module::type
209
+ Example: 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC
210
+
211
+ Args:
212
+ coin_type: Coin type to validate
213
+
214
+ Returns:
215
+ True if valid coin type format
216
+ """
217
+ if not coin_type or not isinstance(coin_type, str):
218
+ return False
219
+
220
+ parts = coin_type.split("::")
221
+ if len(parts) != 3:
222
+ return False
223
+
224
+ package_addr, module_name, type_name = parts
225
+
226
+ # Validate package address
227
+ if not is_valid_sui_address(package_addr):
228
+ return False
229
+
230
+ # Validate module and type names (alphanumeric + underscore)
231
+ import re
232
+ if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', module_name):
233
+ return False
234
+ if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', type_name):
235
+ return False
236
+
237
+ return True
238
+
239
+
240
+ def validate_sui_payload(payload: Dict[str, Any]) -> bool:
241
+ """
242
+ Validate a Sui payment payload structure.
243
+
244
+ The payload must contain:
245
+ - transactionBytes: BCS-encoded TransactionData (base64)
246
+ - senderSignature: User's signature (base64)
247
+ - from: Sender address
248
+ - to: Recipient address
249
+ - amount: Transfer amount (string)
250
+
251
+ Args:
252
+ payload: Payload dictionary from x402 payment
253
+
254
+ Returns:
255
+ True if valid, raises ValueError if invalid
256
+ """
257
+ required_fields = ["transactionBytes", "senderSignature", "from", "to", "amount"]
258
+ for field in required_fields:
259
+ if field not in payload:
260
+ raise ValueError(f"Sui payload missing '{field}' field")
261
+
262
+ # Validate addresses
263
+ if not is_valid_sui_address(payload["from"]):
264
+ raise ValueError(f"Invalid 'from' address: {payload['from']}")
265
+
266
+ if not is_valid_sui_address(payload["to"]):
267
+ raise ValueError(f"Invalid 'to' address: {payload['to']}")
268
+
269
+ # Validate transactionBytes is valid base64
270
+ try:
271
+ tx_bytes = base64.b64decode(payload["transactionBytes"])
272
+ if len(tx_bytes) < 50:
273
+ raise ValueError(f"Transaction bytes too short: {len(tx_bytes)} bytes")
274
+ except Exception as e:
275
+ raise ValueError(f"Invalid transactionBytes: {e}")
276
+
277
+ # Validate senderSignature is valid base64
278
+ try:
279
+ sig_bytes = base64.b64decode(payload["senderSignature"])
280
+ # Sui signatures are typically 64-65 bytes (Ed25519 or Secp256k1)
281
+ if len(sig_bytes) < 64:
282
+ raise ValueError(f"Signature too short: {len(sig_bytes)} bytes")
283
+ except Exception as e:
284
+ raise ValueError(f"Invalid senderSignature: {e}")
285
+
286
+ # Validate amount is numeric
287
+ try:
288
+ amount = int(payload["amount"])
289
+ if amount <= 0:
290
+ raise ValueError(f"Amount must be positive: {amount}")
291
+ except (ValueError, TypeError) as e:
292
+ raise ValueError(f"Invalid amount: {e}")
293
+
294
+ return True
295
+
296
+
297
+ def get_sui_fee_payer(network_name: str = "sui") -> str:
298
+ """
299
+ Get the fee payer (sponsor) address for a Sui network.
300
+
301
+ The fee payer is the facilitator address that sponsors transaction gas.
302
+
303
+ Args:
304
+ network_name: Network name ('sui', 'sui-mainnet', 'sui-testnet')
305
+
306
+ Returns:
307
+ Fee payer address for the specified network
308
+
309
+ Example:
310
+ >>> get_sui_fee_payer("sui")
311
+ '0xe7bbf2b13f7d72714760aa16e024fa1b35a978793f9893d0568a4fbf356a764a'
312
+ >>> get_sui_fee_payer("sui-testnet")
313
+ '0xabbd16a2fab2a502c9cfe835195a6fc7d70bfc27cffb40b8b286b52a97006e67'
314
+ """
315
+ # Use facilitator module if available
316
+ if get_fee_payer is not None:
317
+ fee_payer = get_fee_payer(network_name)
318
+ if fee_payer:
319
+ return fee_payer
320
+
321
+ # Fallback to direct lookup
322
+ network_lower = network_name.lower()
323
+ if "testnet" in network_lower:
324
+ return SUI_FEE_PAYER_TESTNET
325
+ return SUI_FEE_PAYER_MAINNET
326
+
327
+
328
+ def get_sui_usdc_coin_type(network_name: str = "sui") -> str:
329
+ """
330
+ Get the USDC coin type for a Sui network.
331
+
332
+ Args:
333
+ network_name: Network name ('sui', 'sui-mainnet', 'sui-testnet')
334
+
335
+ Returns:
336
+ USDC coin type in package::module::type format
337
+
338
+ Example:
339
+ >>> get_sui_usdc_coin_type("sui")
340
+ '0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'
341
+ """
342
+ network_lower = network_name.lower()
343
+ if "testnet" in network_lower:
344
+ return SUI_USDC_COIN_TYPE_TESTNET
345
+ return SUI_USDC_COIN_TYPE_MAINNET
346
+
347
+
348
+ # =============================================================================
349
+ # Sui Transaction Building Utilities (for reference)
350
+ # =============================================================================
351
+
352
+ # Default gas budget in MIST (1 SUI = 1e9 MIST)
353
+ DEFAULT_GAS_BUDGET = 10_000_000 # 0.01 SUI
354
+
355
+ # Sui object ID length
356
+ SUI_OBJECT_ID_LENGTH = 66 # 0x + 64 hex chars
357
+
358
+ # Sui digest length (base58 encoded)
359
+ SUI_DIGEST_LENGTH = 44 # base58 encoded 32-byte digest
360
+
361
+
362
+ def format_sui_amount(usd_amount: float, decimals: int = 6) -> int:
363
+ """
364
+ Convert USD amount to Sui token base units.
365
+
366
+ Args:
367
+ usd_amount: Amount in USD (e.g., 10.50)
368
+ decimals: Token decimals (6 for USDC)
369
+
370
+ Returns:
371
+ Amount in base units
372
+ """
373
+ return int(usd_amount * (10 ** decimals))
374
+
375
+
376
+ def parse_sui_amount(base_units: int, decimals: int = 6) -> float:
377
+ """
378
+ Convert Sui token base units to USD amount.
379
+
380
+ Args:
381
+ base_units: Amount in base units
382
+ decimals: Token decimals (6 for USDC)
383
+
384
+ Returns:
385
+ Amount in USD
386
+ """
387
+ return base_units / (10 ** decimals)
@@ -1,13 +1,13 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: uvd-x402-sdk
3
- Version: 0.5.2
4
- Summary: Python SDK for x402 payments - gasless crypto payments across 16 blockchains with multi-stablecoin support (USDC, EURC, AUSD, PYUSD, USDT)
3
+ Version: 0.5.4
4
+ Summary: Python SDK for x402 payments - gasless crypto payments across 18 blockchains with multi-stablecoin support (USDC, EURC, AUSD, PYUSD, USDT)
5
5
  Author-email: Ultravioleta DAO <dev@ultravioletadao.xyz>
6
6
  Project-URL: Homepage, https://github.com/UltravioletaDAO/uvd-x402-sdk-python
7
7
  Project-URL: Documentation, https://docs.ultravioletadao.xyz/x402-sdk
8
8
  Project-URL: Repository, https://github.com/UltravioletaDAO/uvd-x402-sdk-python
9
9
  Project-URL: Issues, https://github.com/UltravioletaDAO/uvd-x402-sdk-python/issues
10
- Keywords: x402,payments,crypto,usdc,eurc,stablecoin,web3,evm,solana,near,stellar,algorand,facilitator,gasless,eip-712,eip-3009
10
+ Keywords: x402,payments,crypto,usdc,eurc,stablecoin,web3,evm,solana,near,stellar,algorand,sui,facilitator,gasless,eip-712,eip-3009
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: MIT License
@@ -53,11 +53,13 @@ Requires-Dist: eth-account>=0.10.0; extra == "web3"
53
53
 
54
54
  Python SDK for integrating **x402 cryptocurrency payments** via the Ultravioleta DAO facilitator.
55
55
 
56
- Accept **gasless stablecoin payments** across **14 blockchain networks** with a single integration. The SDK handles signature verification, on-chain settlement, and all the complexity of multi-chain payments.
56
+ Accept **gasless stablecoin payments** across **16 blockchain networks** with a single integration. The SDK handles signature verification, on-chain settlement, and all the complexity of multi-chain payments.
57
+
58
+ **New in v0.5.0+**: The SDK now includes embedded facilitator addresses - no manual configuration needed!
57
59
 
58
60
  ## Features
59
61
 
60
- - **14 Networks**: EVM chains (Base, Ethereum, Polygon, etc.), SVM chains (Solana, Fogo), NEAR, and Stellar
62
+ - **16 Networks**: EVM chains (Base, Ethereum, Polygon, etc.), SVM chains (Solana, Fogo), NEAR, Stellar, and Algorand
61
63
  - **5 Stablecoins**: USDC, EURC, AUSD, PYUSD, USDT (EVM chains)
62
64
  - **x402 v1 & v2**: Full support for both protocol versions with auto-detection
63
65
  - **Framework Integrations**: Flask, FastAPI, Django, AWS Lambda
@@ -95,6 +97,8 @@ print(f"Paid by {result.payer_address}, tx: {result.transaction_hash}")
95
97
  | Fogo | SVM | - | `solana:fogo` | Active |
96
98
  | NEAR | NEAR | - | `near:mainnet` | Active |
97
99
  | Stellar | Stellar | - | `stellar:pubnet` | Active |
100
+ | Algorand | Algorand | - | `algorand:mainnet` | Active |
101
+ | Algorand Testnet | Algorand | - | `algorand:testnet` | Active |
98
102
 
99
103
  ### Supported Tokens (EVM Chains)
100
104
 
@@ -117,6 +121,7 @@ pip install uvd-x402-sdk[flask] # Flask integration
117
121
  pip install uvd-x402-sdk[fastapi] # FastAPI/Starlette integration
118
122
  pip install uvd-x402-sdk[django] # Django integration
119
123
  pip install uvd-x402-sdk[aws] # AWS Lambda helpers
124
+ pip install uvd-x402-sdk[algorand] # Algorand atomic group helpers
120
125
 
121
126
  # All integrations
122
127
  pip install uvd-x402-sdk[all]
@@ -375,6 +380,65 @@ from uvd_x402_sdk.networks.near import validate_near_payload
375
380
  validate_near_payload(payload.payload) # Raises ValueError if invalid
376
381
  ```
377
382
 
383
+ ### Algorand
384
+
385
+ Algorand uses atomic groups with ASA (Algorand Standard Assets) transfers.
386
+
387
+ ```python
388
+ from uvd_x402_sdk import X402Client, X402Config
389
+
390
+ config = X402Config(
391
+ recipient_algorand="NCDSNUQ2QLXDMJXRALAW4CRUSSKG4IS37MVOFDQQPC45SE4EBZO42U6ZX4",
392
+ supported_networks=["algorand"],
393
+ )
394
+
395
+ client = X402Client(config=config)
396
+ result = client.process_payment(x_payment_header, Decimal("1.00"))
397
+
398
+ # Algorand uses atomic groups: [fee_tx, payment_tx]
399
+ from uvd_x402_sdk.networks.algorand import (
400
+ validate_algorand_payload,
401
+ get_algorand_fee_payer,
402
+ build_atomic_group,
403
+ )
404
+
405
+ # Get the facilitator fee payer address
406
+ fee_payer = get_algorand_fee_payer("algorand")
407
+ print(f"Fee payer: {fee_payer}") # KIMS5H6Q...
408
+
409
+ # Validate payload structure
410
+ payload = client.extract_payload(x_payment_header)
411
+ validate_algorand_payload(payload.payload) # Raises ValueError if invalid
412
+ ```
413
+
414
+ #### Building Algorand Payments (requires `pip install uvd-x402-sdk[algorand]`)
415
+
416
+ ```python
417
+ from uvd_x402_sdk.networks.algorand import (
418
+ build_atomic_group,
419
+ build_x402_payment_request,
420
+ get_algorand_fee_payer,
421
+ )
422
+ from algosdk.v2client import algod
423
+
424
+ # Connect to Algorand node
425
+ client = algod.AlgodClient("", "https://mainnet-api.algonode.cloud")
426
+
427
+ # Build atomic group
428
+ payload = build_atomic_group(
429
+ sender_address="YOUR_ADDRESS...",
430
+ recipient_address="MERCHANT_ADDRESS...",
431
+ amount=1000000, # 1 USDC (6 decimals)
432
+ asset_id=31566704, # USDC ASA ID on mainnet
433
+ facilitator_address=get_algorand_fee_payer("algorand"),
434
+ sign_transaction=lambda txn: txn.sign(private_key),
435
+ algod_client=client,
436
+ )
437
+
438
+ # Build x402 payment request
439
+ request = build_x402_payment_request(payload, network="algorand")
440
+ ```
441
+
378
442
  ---
379
443
 
380
444
  ## x402 v1 vs v2
@@ -593,6 +657,94 @@ config = X402Config.from_env()
593
657
 
594
658
  ---
595
659
 
660
+ ## Facilitator Addresses
661
+
662
+ The SDK includes all facilitator addresses as embedded constants. You don't need to configure them manually.
663
+
664
+ ### Fee Payer Addresses (Non-EVM)
665
+
666
+ Non-EVM chains require a fee payer address for gasless transactions:
667
+
668
+ ```python
669
+ from uvd_x402_sdk import (
670
+ # Algorand
671
+ ALGORAND_FEE_PAYER_MAINNET, # KIMS5H6QLCUDL65L5UBTOXDPWLMTS7N3AAC3I6B2NCONEI5QIVK7LH2C2I
672
+ ALGORAND_FEE_PAYER_TESTNET, # 5DPPDQNYUPCTXRZWRYSF3WPYU6RKAUR25F3YG4EKXQRHV5AUAI62H5GXL4
673
+
674
+ # Solana
675
+ SOLANA_FEE_PAYER_MAINNET, # F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq
676
+ SOLANA_FEE_PAYER_DEVNET, # 6xNPewUdKRbEZDReQdpyfNUdgNg8QRc8Mt263T5GZSRv
677
+
678
+ # Fogo
679
+ FOGO_FEE_PAYER_MAINNET, # F742C4VfFLQ9zRQyithoj5229ZgtX2WqKCSFKgH2EThq
680
+ FOGO_FEE_PAYER_TESTNET, # 6xNPewUdKRbEZDReQdpyfNUdgNg8QRc8Mt263T5GZSRv
681
+
682
+ # NEAR
683
+ NEAR_FEE_PAYER_MAINNET, # uvd-facilitator.near
684
+ NEAR_FEE_PAYER_TESTNET, # uvd-facilitator.testnet
685
+
686
+ # Stellar
687
+ STELLAR_FEE_PAYER_MAINNET, # GCHPGXJT2WFFRFCA5TV4G4E3PMMXLNIDUH27PKDYA4QJ2XGYZWGFZNHB
688
+ STELLAR_FEE_PAYER_TESTNET, # GBBFZMLUJEZVI32EN4XA2KPP445XIBTMTRBLYWFIL556RDTHS2OWFQ2Z
689
+
690
+ # Helper function
691
+ get_fee_payer, # Get fee payer for any network
692
+ )
693
+
694
+ # Get fee payer for any network
695
+ fee_payer = get_fee_payer("algorand") # Returns KIMS5H6Q...
696
+ fee_payer = get_fee_payer("solana") # Returns F742C4VfF...
697
+ fee_payer = get_fee_payer("base") # Returns None (EVM doesn't need fee payer)
698
+ ```
699
+
700
+ ### EVM Facilitator Addresses
701
+
702
+ EVM chains use EIP-3009 transferWithAuthorization (gasless by design), but the facilitator wallet addresses are available for reference:
703
+
704
+ ```python
705
+ from uvd_x402_sdk import (
706
+ EVM_FACILITATOR_MAINNET, # 0x103040545AC5031A11E8C03dd11324C7333a13C7
707
+ EVM_FACILITATOR_TESTNET, # 0x34033041a5944B8F10f8E4D8496Bfb84f1A293A8
708
+ )
709
+ ```
710
+
711
+ ### Helper Functions
712
+
713
+ ```python
714
+ from uvd_x402_sdk import (
715
+ get_fee_payer, # Get fee payer address for a network
716
+ requires_fee_payer, # Check if network needs fee payer
717
+ get_all_fee_payers, # Get all registered fee payers
718
+ build_payment_info, # Build payment info with auto feePayer
719
+ DEFAULT_FACILITATOR_URL, # https://facilitator.ultravioletadao.xyz
720
+ )
721
+
722
+ # Check if network needs fee payer
723
+ requires_fee_payer("algorand") # True
724
+ requires_fee_payer("base") # False
725
+
726
+ # Build payment info with automatic fee payer
727
+ info = build_payment_info(
728
+ network="algorand",
729
+ pay_to="MERCHANT_ADDRESS...",
730
+ max_amount_required="1000000",
731
+ description="API access"
732
+ )
733
+ # info = {
734
+ # 'network': 'algorand',
735
+ # 'payTo': 'MERCHANT_ADDRESS...',
736
+ # 'maxAmountRequired': '1000000',
737
+ # 'description': 'API access',
738
+ # 'asset': '31566704',
739
+ # 'extra': {
740
+ # 'token': 'usdc',
741
+ # 'feePayer': 'KIMS5H6QLCUDL65L5UBTOXDPWLMTS7N3AAC3I6B2NCONEI5QIVK7LH2C2I'
742
+ # }
743
+ # }
744
+ ```
745
+
746
+ ---
747
+
596
748
  ## Registering Custom Networks
597
749
 
598
750
  ```python
@@ -823,6 +975,7 @@ The facilitator (https://facilitator.ultravioletadao.xyz) handles all on-chain i
823
975
  | SVM | Partial transaction | Co-signs + submits transaction |
824
976
  | NEAR | DelegateAction (Borsh) | Wraps in `Action::Delegate` |
825
977
  | Stellar | Auth entry (XDR) | Wraps in fee-bump transaction |
978
+ | Algorand | ASA transfer tx | Signs fee tx + submits atomic group |
826
979
 
827
980
  ---
828
981
 
@@ -929,6 +1082,46 @@ MIT License - see LICENSE file.
929
1082
 
930
1083
  ## Changelog
931
1084
 
1085
+ ### v0.5.2 (2025-12-26)
1086
+
1087
+ - Added EVM facilitator addresses for reference
1088
+ - `EVM_FACILITATOR_MAINNET`: 0x103040545AC5031A11E8C03dd11324C7333a13C7
1089
+ - `EVM_FACILITATOR_TESTNET`: 0x34033041a5944B8F10f8E4D8496Bfb84f1A293A8
1090
+
1091
+ ### v0.5.1 (2025-12-26)
1092
+
1093
+ - Changed default Algorand mainnet network name from `algorand-mainnet` to `algorand`
1094
+ - Aligns with facilitator v1.9.5+ which now uses `algorand` as the primary network identifier
1095
+
1096
+ ### v0.5.0 (2025-12-26)
1097
+
1098
+ - **Facilitator Module**: Added `facilitator.py` with all fee payer addresses embedded as constants
1099
+ - SDK users no longer need to configure facilitator addresses manually
1100
+ - Added constants: `ALGORAND_FEE_PAYER_MAINNET`, `SOLANA_FEE_PAYER_MAINNET`, `NEAR_FEE_PAYER_MAINNET`, `STELLAR_FEE_PAYER_MAINNET`, etc.
1101
+ - Added helper functions: `get_fee_payer()`, `requires_fee_payer()`, `build_payment_info()`
1102
+ - Network-specific helpers: `get_algorand_fee_payer()`, `get_svm_fee_payer()`, `get_near_fee_payer()`, `get_stellar_fee_payer()`
1103
+
1104
+ ### v0.4.2 (2025-12-26)
1105
+
1106
+ - **Algorand Atomic Group Fix**: Rewrote Algorand payload format to use GoPlausible x402-avm atomic group spec
1107
+ - New `AlgorandPaymentPayload` dataclass with `paymentIndex` and `paymentGroup` fields
1108
+ - Added `build_atomic_group()` helper for constructing two-transaction atomic groups
1109
+ - Added `validate_algorand_payload()` for payload validation
1110
+ - Added `build_x402_payment_request()` for building complete x402 requests
1111
+
1112
+ ### v0.4.1 (2025-12-26)
1113
+
1114
+ - Added AUSD (Agora USD) support on Solana using Token2022 program
1115
+ - Added `TOKEN_2022_PROGRAM_ID` constant
1116
+ - Added `get_token_program_id()` and `is_token_2022()` helpers
1117
+
1118
+ ### v0.4.0 (2025-12-26)
1119
+
1120
+ - **Algorand Support**: Added Algorand mainnet and testnet networks
1121
+ - Added `ALGORAND` NetworkType
1122
+ - Added `algorand` optional dependency (`py-algorand-sdk>=2.0.0`)
1123
+ - SDK now supports 16 blockchain networks
1124
+
932
1125
  ### v0.3.4 (2025-12-22)
933
1126
 
934
1127
  - Added USDT support (USDT0 omnichain via LayerZero) on Ethereum, Arbitrum, Optimism, Avalanche, Polygon
@@ -1,9 +1,9 @@
1
- uvd_x402_sdk/__init__.py,sha256=lLRZonhKdxY7yuLDX1owQxqQlaBeDP9GbfJ2fvScpOA,6429
1
+ uvd_x402_sdk/__init__.py,sha256=PMSWL2YXzdKZR5Gq_JueGLE4QidfKTD9RqtSMprUyuc,6577
2
2
  uvd_x402_sdk/client.py,sha256=QbK22DtC3HmvvCezphQ-UsYX468vKrIN-M_wF4pv9cM,18389
3
3
  uvd_x402_sdk/config.py,sha256=BNGnX2RwZ_ELIcSKU7RkwTUcln4LMFZdCwG1ptASKN8,8644
4
4
  uvd_x402_sdk/decorators.py,sha256=XJ7V4554hsa-AVDrizF1oKmeTysg5zlkQRcaeGBI73E,9767
5
5
  uvd_x402_sdk/exceptions.py,sha256=kzYNHFn41dSOZ5HaBDrbf4tdwJYQs1YcU9YybTrGZxo,6527
6
- uvd_x402_sdk/facilitator.py,sha256=zidXzCnCJvKmK4LPXoLldslZqhKgyO8uY_hCZlJdvGs,12323
6
+ uvd_x402_sdk/facilitator.py,sha256=OgmB-4GDu9HvG-C6DprMd4h-3neSwsxVuC5-NffVwVI,12776
7
7
  uvd_x402_sdk/models.py,sha256=nfA8Ak0pyIveiNpstjqxnQ6-aPQ8TRJzJq2LJwlJc-E,14282
8
8
  uvd_x402_sdk/response.py,sha256=4wxH4kWg1F8pokKEbN1kDvDF55cQxmQUN88HTxXht8g,13608
9
9
  uvd_x402_sdk/integrations/__init__.py,sha256=Hq1Y0YIMYWBAtmbOLXDC40KQuCrbSpQVjAqEsbjH56s,1912
@@ -11,15 +11,16 @@ uvd_x402_sdk/integrations/django_integration.py,sha256=e3xaV1Yz3HHI7zZBNcyTmV0Js
11
11
  uvd_x402_sdk/integrations/fastapi_integration.py,sha256=j5h1IJwFLBBoWov7ANLCFaxeCa8pugn-XU9ibrzIL0Y,10205
12
12
  uvd_x402_sdk/integrations/flask_integration.py,sha256=0iQKO5-WRxE76Pv-1jEl4lYhjCLmq_R-jxR5g9xIcKw,8825
13
13
  uvd_x402_sdk/integrations/lambda_integration.py,sha256=nRf4o3nS6Syx-d5P0kEhz66y7jb_S4w-mwaIazgiA9c,10184
14
- uvd_x402_sdk/networks/__init__.py,sha256=LKl_TljVoCDb27YB4X_VbQN8XKbdwWFAsCwgiqQtlgo,2092
14
+ uvd_x402_sdk/networks/__init__.py,sha256=3cGi6v9mVa1NyDasB2JS1AdsRxidr8za9qGYg06kW_M,2097
15
15
  uvd_x402_sdk/networks/algorand.py,sha256=kyet3mu8Uf454QAM6PHQ1FWuQetpPQ7D0jtj7dfojsc,19433
16
- uvd_x402_sdk/networks/base.py,sha256=gOPWfqasGbgtg9w2uG5pWnfjdOEain92L2egnDSBguc,14863
16
+ uvd_x402_sdk/networks/base.py,sha256=P-wTw3LnLZnd_Gv2NPsdcCZZMQb_yDY_NdEMvnstRhY,15421
17
17
  uvd_x402_sdk/networks/evm.py,sha256=4IbeaMH2I1c9DYCijghys0qYNeL2Nl92IMKLwq-b0Zg,10065
18
18
  uvd_x402_sdk/networks/near.py,sha256=HMMWJr-Jckj3YQTbSXkavlJWZB7ZV8OQX0bq8DuVxIg,12990
19
19
  uvd_x402_sdk/networks/solana.py,sha256=GVUeh0O2W6f8Vbgoom2UQSGI8joZV68Pnpzhh87Bnqg,13640
20
20
  uvd_x402_sdk/networks/stellar.py,sha256=ZuF-crx41N9MxSsgf2kAy88fsM-xvDyXY_D2ND6M71Y,5142
21
- uvd_x402_sdk-0.5.2.dist-info/LICENSE,sha256=OcLzB_iSgMbvk7b0dlyvleY_IbL2WUaPxvn1CHw2uAc,1073
22
- uvd_x402_sdk-0.5.2.dist-info/METADATA,sha256=-LP-c2xZTdyYZNk_prfgZexH3R_OEC8URkEhU_DchVE,29711
23
- uvd_x402_sdk-0.5.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
24
- uvd_x402_sdk-0.5.2.dist-info/top_level.txt,sha256=Exyjj_Kl7CDAGFMi72lT9oFPOYiRNZb3l8tr906mMmc,13
25
- uvd_x402_sdk-0.5.2.dist-info/RECORD,,
21
+ uvd_x402_sdk/networks/sui.py,sha256=klDXZ2gLnHlRt5qrv4_Vu7P2qof_WMwbv3mMfL0AQ34,11356
22
+ uvd_x402_sdk-0.5.4.dist-info/LICENSE,sha256=OcLzB_iSgMbvk7b0dlyvleY_IbL2WUaPxvn1CHw2uAc,1073
23
+ uvd_x402_sdk-0.5.4.dist-info/METADATA,sha256=oKeeArzQ44uDq5wyj3Q8LCKoJIf5mz-GfhAKRMXmf-w,36537
24
+ uvd_x402_sdk-0.5.4.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
25
+ uvd_x402_sdk-0.5.4.dist-info/top_level.txt,sha256=Exyjj_Kl7CDAGFMi72lT9oFPOYiRNZb3l8tr906mMmc,13
26
+ uvd_x402_sdk-0.5.4.dist-info/RECORD,,