uvd-x402-sdk 0.5.2__py3-none-any.whl → 0.5.5__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 +7 -2
- uvd_x402_sdk/facilitator.py +11 -0
- uvd_x402_sdk/networks/__init__.py +1 -1
- uvd_x402_sdk/networks/base.py +16 -0
- uvd_x402_sdk/networks/sui.py +424 -0
- {uvd_x402_sdk-0.5.2.dist-info → uvd_x402_sdk-0.5.5.dist-info}/METADATA +198 -5
- {uvd_x402_sdk-0.5.2.dist-info → uvd_x402_sdk-0.5.5.dist-info}/RECORD +10 -9
- {uvd_x402_sdk-0.5.2.dist-info → uvd_x402_sdk-0.5.5.dist-info}/LICENSE +0 -0
- {uvd_x402_sdk-0.5.2.dist-info → uvd_x402_sdk-0.5.5.dist-info}/WHEEL +0 -0
- {uvd_x402_sdk-0.5.2.dist-info → uvd_x402_sdk-0.5.5.dist-info}/top_level.txt +0 -0
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 (
|
|
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.
|
|
45
|
+
__version__ = "0.5.5"
|
|
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",
|
uvd_x402_sdk/facilitator.py
CHANGED
|
@@ -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
|
uvd_x402_sdk/networks/base.py
CHANGED
|
@@ -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,424 @@
|
|
|
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
|
+
- AUSD: Agora USD (mainnet only)
|
|
11
|
+
|
|
12
|
+
All Sui chains use the same payment flow:
|
|
13
|
+
1. User creates a programmable transaction for token transfer
|
|
14
|
+
2. User signs the transaction
|
|
15
|
+
3. Transaction is sent to the facilitator with the user's signature
|
|
16
|
+
4. Facilitator sponsors the transaction (pays gas in SUI)
|
|
17
|
+
5. Facilitator adds sponsor signature and submits to Sui network
|
|
18
|
+
|
|
19
|
+
Transaction Structure:
|
|
20
|
+
- Programmable Transaction Block (PTB) for USDC transfer
|
|
21
|
+
- TransferObjects or SplitCoins + TransferObjects commands
|
|
22
|
+
- Facilitator is gas sponsor (user pays ZERO SUI)
|
|
23
|
+
|
|
24
|
+
Key differences from other chains:
|
|
25
|
+
- Uses Move-based programmable transactions
|
|
26
|
+
- BCS (Binary Canonical Serialization) encoding
|
|
27
|
+
- 66-character addresses (0x + 64 hex)
|
|
28
|
+
- Coin types in format: package::module::type
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
import base64
|
|
32
|
+
from typing import Dict, Any, Optional
|
|
33
|
+
|
|
34
|
+
from uvd_x402_sdk.networks.base import (
|
|
35
|
+
NetworkConfig,
|
|
36
|
+
NetworkType,
|
|
37
|
+
TokenConfig,
|
|
38
|
+
register_network,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Sui fee payer addresses (facilitator wallets)
|
|
42
|
+
try:
|
|
43
|
+
from uvd_x402_sdk.facilitator import (
|
|
44
|
+
SUI_FEE_PAYER_MAINNET,
|
|
45
|
+
SUI_FEE_PAYER_TESTNET,
|
|
46
|
+
get_fee_payer,
|
|
47
|
+
)
|
|
48
|
+
except ImportError:
|
|
49
|
+
# Fallback if facilitator module not loaded yet
|
|
50
|
+
SUI_FEE_PAYER_MAINNET = "0xe7bbf2b13f7d72714760aa16e024fa1b35a978793f9893d0568a4fbf356a764a"
|
|
51
|
+
SUI_FEE_PAYER_TESTNET = "0xabbd16a2fab2a502c9cfe835195a6fc7d70bfc27cffb40b8b286b52a97006e67"
|
|
52
|
+
get_fee_payer = None # type: ignore
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# =============================================================================
|
|
56
|
+
# Sui Networks Configuration
|
|
57
|
+
# =============================================================================
|
|
58
|
+
|
|
59
|
+
# USDC coin types on Sui
|
|
60
|
+
SUI_USDC_COIN_TYPE_MAINNET = "0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC"
|
|
61
|
+
SUI_USDC_COIN_TYPE_TESTNET = "0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC"
|
|
62
|
+
|
|
63
|
+
# AUSD (Agora USD) coin types on Sui
|
|
64
|
+
SUI_AUSD_COIN_TYPE_MAINNET = "0x2053d08c1e2bd02791056171aab0fd12bd7cd7efad2ab8f6b9c8902f14df2ff2::ausd::AUSD"
|
|
65
|
+
|
|
66
|
+
# Sui Mainnet
|
|
67
|
+
SUI = NetworkConfig(
|
|
68
|
+
name="sui",
|
|
69
|
+
display_name="Sui",
|
|
70
|
+
network_type=NetworkType.SUI,
|
|
71
|
+
chain_id=0, # Non-EVM, no chain ID
|
|
72
|
+
usdc_address=SUI_USDC_COIN_TYPE_MAINNET,
|
|
73
|
+
usdc_decimals=6,
|
|
74
|
+
usdc_domain_name="", # Not applicable for Sui
|
|
75
|
+
usdc_domain_version="",
|
|
76
|
+
rpc_url="https://fullnode.mainnet.sui.io:443",
|
|
77
|
+
enabled=True,
|
|
78
|
+
tokens={
|
|
79
|
+
"usdc": TokenConfig(
|
|
80
|
+
address=SUI_USDC_COIN_TYPE_MAINNET,
|
|
81
|
+
decimals=6,
|
|
82
|
+
name="", # Not applicable for Sui
|
|
83
|
+
version="",
|
|
84
|
+
),
|
|
85
|
+
"ausd": TokenConfig(
|
|
86
|
+
address=SUI_AUSD_COIN_TYPE_MAINNET,
|
|
87
|
+
decimals=6,
|
|
88
|
+
name="", # Not applicable for Sui
|
|
89
|
+
version="",
|
|
90
|
+
),
|
|
91
|
+
},
|
|
92
|
+
extra_config={
|
|
93
|
+
# Coin type for USDC (package::module::type format)
|
|
94
|
+
"usdc_coin_type": SUI_USDC_COIN_TYPE_MAINNET,
|
|
95
|
+
# Coin type for AUSD (Agora USD)
|
|
96
|
+
"ausd_coin_type": SUI_AUSD_COIN_TYPE_MAINNET,
|
|
97
|
+
# Fee payer (facilitator) address
|
|
98
|
+
"fee_payer": SUI_FEE_PAYER_MAINNET,
|
|
99
|
+
# Block explorer
|
|
100
|
+
"explorer_url": "https://suiscan.xyz",
|
|
101
|
+
# Network identifier
|
|
102
|
+
"sui_network": "mainnet",
|
|
103
|
+
# Gas budget (in MIST, 1 SUI = 1e9 MIST)
|
|
104
|
+
"default_gas_budget": 10_000_000, # 0.01 SUI
|
|
105
|
+
},
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Sui Testnet
|
|
109
|
+
SUI_TESTNET = NetworkConfig(
|
|
110
|
+
name="sui-testnet",
|
|
111
|
+
display_name="Sui Testnet",
|
|
112
|
+
network_type=NetworkType.SUI,
|
|
113
|
+
chain_id=0, # Non-EVM, no chain ID
|
|
114
|
+
usdc_address=SUI_USDC_COIN_TYPE_TESTNET,
|
|
115
|
+
usdc_decimals=6,
|
|
116
|
+
usdc_domain_name="", # Not applicable for Sui
|
|
117
|
+
usdc_domain_version="",
|
|
118
|
+
rpc_url="https://fullnode.testnet.sui.io:443",
|
|
119
|
+
enabled=True,
|
|
120
|
+
tokens={
|
|
121
|
+
"usdc": TokenConfig(
|
|
122
|
+
address=SUI_USDC_COIN_TYPE_TESTNET,
|
|
123
|
+
decimals=6,
|
|
124
|
+
name="", # Not applicable for Sui
|
|
125
|
+
version="",
|
|
126
|
+
),
|
|
127
|
+
},
|
|
128
|
+
extra_config={
|
|
129
|
+
# Coin type for USDC (package::module::type format)
|
|
130
|
+
"usdc_coin_type": SUI_USDC_COIN_TYPE_TESTNET,
|
|
131
|
+
# Fee payer (facilitator) address
|
|
132
|
+
"fee_payer": SUI_FEE_PAYER_TESTNET,
|
|
133
|
+
# Block explorer
|
|
134
|
+
"explorer_url": "https://suiscan.xyz/testnet",
|
|
135
|
+
# Network identifier
|
|
136
|
+
"sui_network": "testnet",
|
|
137
|
+
# Gas budget (in MIST, 1 SUI = 1e9 MIST)
|
|
138
|
+
"default_gas_budget": 10_000_000, # 0.01 SUI
|
|
139
|
+
},
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Register Sui networks
|
|
143
|
+
register_network(SUI)
|
|
144
|
+
register_network(SUI_TESTNET)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# =============================================================================
|
|
148
|
+
# Sui-specific utilities
|
|
149
|
+
# =============================================================================
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def is_sui_network(network_name: str) -> bool:
|
|
153
|
+
"""
|
|
154
|
+
Check if a network is Sui-based.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
network_name: Network name to check
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
True if network uses Sui
|
|
161
|
+
"""
|
|
162
|
+
from uvd_x402_sdk.networks.base import get_network, NetworkType
|
|
163
|
+
|
|
164
|
+
network = get_network(network_name)
|
|
165
|
+
if not network:
|
|
166
|
+
return False
|
|
167
|
+
return NetworkType.is_sui(network.network_type)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def get_sui_networks() -> list:
|
|
171
|
+
"""
|
|
172
|
+
Get all registered Sui networks.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
List of Sui NetworkConfig instances
|
|
176
|
+
"""
|
|
177
|
+
from uvd_x402_sdk.networks.base import list_networks, NetworkType
|
|
178
|
+
|
|
179
|
+
return [
|
|
180
|
+
n for n in list_networks(enabled_only=True)
|
|
181
|
+
if NetworkType.is_sui(n.network_type)
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def is_valid_sui_address(address: str) -> bool:
|
|
186
|
+
"""
|
|
187
|
+
Validate a Sui address format.
|
|
188
|
+
|
|
189
|
+
Sui addresses are 66 characters: 0x + 64 hex characters.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
address: Address to validate
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
True if valid Sui address
|
|
196
|
+
"""
|
|
197
|
+
if not address or not isinstance(address, str):
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
# Sui addresses start with 0x and have 64 hex characters after
|
|
201
|
+
if not address.startswith("0x"):
|
|
202
|
+
return False
|
|
203
|
+
|
|
204
|
+
hex_part = address[2:]
|
|
205
|
+
if len(hex_part) != 64:
|
|
206
|
+
return False
|
|
207
|
+
|
|
208
|
+
# Validate hex characters
|
|
209
|
+
try:
|
|
210
|
+
int(hex_part, 16)
|
|
211
|
+
return True
|
|
212
|
+
except ValueError:
|
|
213
|
+
return False
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def is_valid_sui_coin_type(coin_type: str) -> bool:
|
|
217
|
+
"""
|
|
218
|
+
Validate a Sui coin type format.
|
|
219
|
+
|
|
220
|
+
Sui coin types follow format: package_address::module::type
|
|
221
|
+
Example: 0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
coin_type: Coin type to validate
|
|
225
|
+
|
|
226
|
+
Returns:
|
|
227
|
+
True if valid coin type format
|
|
228
|
+
"""
|
|
229
|
+
if not coin_type or not isinstance(coin_type, str):
|
|
230
|
+
return False
|
|
231
|
+
|
|
232
|
+
parts = coin_type.split("::")
|
|
233
|
+
if len(parts) != 3:
|
|
234
|
+
return False
|
|
235
|
+
|
|
236
|
+
package_addr, module_name, type_name = parts
|
|
237
|
+
|
|
238
|
+
# Validate package address
|
|
239
|
+
if not is_valid_sui_address(package_addr):
|
|
240
|
+
return False
|
|
241
|
+
|
|
242
|
+
# Validate module and type names (alphanumeric + underscore)
|
|
243
|
+
import re
|
|
244
|
+
if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', module_name):
|
|
245
|
+
return False
|
|
246
|
+
if not re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', type_name):
|
|
247
|
+
return False
|
|
248
|
+
|
|
249
|
+
return True
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def validate_sui_payload(payload: Dict[str, Any]) -> bool:
|
|
253
|
+
"""
|
|
254
|
+
Validate a Sui payment payload structure.
|
|
255
|
+
|
|
256
|
+
The payload must contain:
|
|
257
|
+
- transactionBytes: BCS-encoded TransactionData (base64)
|
|
258
|
+
- senderSignature: User's signature (base64)
|
|
259
|
+
- from: Sender address
|
|
260
|
+
- to: Recipient address
|
|
261
|
+
- amount: Transfer amount (string)
|
|
262
|
+
|
|
263
|
+
Args:
|
|
264
|
+
payload: Payload dictionary from x402 payment
|
|
265
|
+
|
|
266
|
+
Returns:
|
|
267
|
+
True if valid, raises ValueError if invalid
|
|
268
|
+
"""
|
|
269
|
+
required_fields = ["transactionBytes", "senderSignature", "from", "to", "amount"]
|
|
270
|
+
for field in required_fields:
|
|
271
|
+
if field not in payload:
|
|
272
|
+
raise ValueError(f"Sui payload missing '{field}' field")
|
|
273
|
+
|
|
274
|
+
# Validate addresses
|
|
275
|
+
if not is_valid_sui_address(payload["from"]):
|
|
276
|
+
raise ValueError(f"Invalid 'from' address: {payload['from']}")
|
|
277
|
+
|
|
278
|
+
if not is_valid_sui_address(payload["to"]):
|
|
279
|
+
raise ValueError(f"Invalid 'to' address: {payload['to']}")
|
|
280
|
+
|
|
281
|
+
# Validate transactionBytes is valid base64
|
|
282
|
+
try:
|
|
283
|
+
tx_bytes = base64.b64decode(payload["transactionBytes"])
|
|
284
|
+
if len(tx_bytes) < 50:
|
|
285
|
+
raise ValueError(f"Transaction bytes too short: {len(tx_bytes)} bytes")
|
|
286
|
+
except Exception as e:
|
|
287
|
+
raise ValueError(f"Invalid transactionBytes: {e}")
|
|
288
|
+
|
|
289
|
+
# Validate senderSignature is valid base64
|
|
290
|
+
try:
|
|
291
|
+
sig_bytes = base64.b64decode(payload["senderSignature"])
|
|
292
|
+
# Sui signatures are typically 64-65 bytes (Ed25519 or Secp256k1)
|
|
293
|
+
if len(sig_bytes) < 64:
|
|
294
|
+
raise ValueError(f"Signature too short: {len(sig_bytes)} bytes")
|
|
295
|
+
except Exception as e:
|
|
296
|
+
raise ValueError(f"Invalid senderSignature: {e}")
|
|
297
|
+
|
|
298
|
+
# Validate amount is numeric
|
|
299
|
+
try:
|
|
300
|
+
amount = int(payload["amount"])
|
|
301
|
+
if amount <= 0:
|
|
302
|
+
raise ValueError(f"Amount must be positive: {amount}")
|
|
303
|
+
except (ValueError, TypeError) as e:
|
|
304
|
+
raise ValueError(f"Invalid amount: {e}")
|
|
305
|
+
|
|
306
|
+
return True
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def get_sui_fee_payer(network_name: str = "sui") -> str:
|
|
310
|
+
"""
|
|
311
|
+
Get the fee payer (sponsor) address for a Sui network.
|
|
312
|
+
|
|
313
|
+
The fee payer is the facilitator address that sponsors transaction gas.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
network_name: Network name ('sui', 'sui-mainnet', 'sui-testnet')
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
Fee payer address for the specified network
|
|
320
|
+
|
|
321
|
+
Example:
|
|
322
|
+
>>> get_sui_fee_payer("sui")
|
|
323
|
+
'0xe7bbf2b13f7d72714760aa16e024fa1b35a978793f9893d0568a4fbf356a764a'
|
|
324
|
+
>>> get_sui_fee_payer("sui-testnet")
|
|
325
|
+
'0xabbd16a2fab2a502c9cfe835195a6fc7d70bfc27cffb40b8b286b52a97006e67'
|
|
326
|
+
"""
|
|
327
|
+
# Use facilitator module if available
|
|
328
|
+
if get_fee_payer is not None:
|
|
329
|
+
fee_payer = get_fee_payer(network_name)
|
|
330
|
+
if fee_payer:
|
|
331
|
+
return fee_payer
|
|
332
|
+
|
|
333
|
+
# Fallback to direct lookup
|
|
334
|
+
network_lower = network_name.lower()
|
|
335
|
+
if "testnet" in network_lower:
|
|
336
|
+
return SUI_FEE_PAYER_TESTNET
|
|
337
|
+
return SUI_FEE_PAYER_MAINNET
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def get_sui_usdc_coin_type(network_name: str = "sui") -> str:
|
|
341
|
+
"""
|
|
342
|
+
Get the USDC coin type for a Sui network.
|
|
343
|
+
|
|
344
|
+
Args:
|
|
345
|
+
network_name: Network name ('sui', 'sui-mainnet', 'sui-testnet')
|
|
346
|
+
|
|
347
|
+
Returns:
|
|
348
|
+
USDC coin type in package::module::type format
|
|
349
|
+
|
|
350
|
+
Example:
|
|
351
|
+
>>> get_sui_usdc_coin_type("sui")
|
|
352
|
+
'0xdba34672e30cb065b1f93e3ab55318768fd6fef66c15942c9f7cb846e2f900e7::usdc::USDC'
|
|
353
|
+
"""
|
|
354
|
+
network_lower = network_name.lower()
|
|
355
|
+
if "testnet" in network_lower:
|
|
356
|
+
return SUI_USDC_COIN_TYPE_TESTNET
|
|
357
|
+
return SUI_USDC_COIN_TYPE_MAINNET
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def get_sui_ausd_coin_type(network_name: str = "sui") -> Optional[str]:
|
|
361
|
+
"""
|
|
362
|
+
Get the AUSD (Agora USD) coin type for a Sui network.
|
|
363
|
+
|
|
364
|
+
Note: AUSD is only available on Sui mainnet.
|
|
365
|
+
|
|
366
|
+
Args:
|
|
367
|
+
network_name: Network name ('sui', 'sui-mainnet', 'sui-testnet')
|
|
368
|
+
|
|
369
|
+
Returns:
|
|
370
|
+
AUSD coin type in package::module::type format, or None if not available
|
|
371
|
+
|
|
372
|
+
Example:
|
|
373
|
+
>>> get_sui_ausd_coin_type("sui")
|
|
374
|
+
'0x2053d08c1e2bd02791056171aab0fd12bd7cd7efad2ab8f6b9c8902f14df2ff2::ausd::AUSD'
|
|
375
|
+
>>> get_sui_ausd_coin_type("sui-testnet")
|
|
376
|
+
None
|
|
377
|
+
"""
|
|
378
|
+
network_lower = network_name.lower()
|
|
379
|
+
# AUSD is only available on Sui mainnet
|
|
380
|
+
if "testnet" in network_lower:
|
|
381
|
+
return None
|
|
382
|
+
return SUI_AUSD_COIN_TYPE_MAINNET
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
# =============================================================================
|
|
386
|
+
# Sui Transaction Building Utilities (for reference)
|
|
387
|
+
# =============================================================================
|
|
388
|
+
|
|
389
|
+
# Default gas budget in MIST (1 SUI = 1e9 MIST)
|
|
390
|
+
DEFAULT_GAS_BUDGET = 10_000_000 # 0.01 SUI
|
|
391
|
+
|
|
392
|
+
# Sui object ID length
|
|
393
|
+
SUI_OBJECT_ID_LENGTH = 66 # 0x + 64 hex chars
|
|
394
|
+
|
|
395
|
+
# Sui digest length (base58 encoded)
|
|
396
|
+
SUI_DIGEST_LENGTH = 44 # base58 encoded 32-byte digest
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def format_sui_amount(usd_amount: float, decimals: int = 6) -> int:
|
|
400
|
+
"""
|
|
401
|
+
Convert USD amount to Sui token base units.
|
|
402
|
+
|
|
403
|
+
Args:
|
|
404
|
+
usd_amount: Amount in USD (e.g., 10.50)
|
|
405
|
+
decimals: Token decimals (6 for USDC)
|
|
406
|
+
|
|
407
|
+
Returns:
|
|
408
|
+
Amount in base units
|
|
409
|
+
"""
|
|
410
|
+
return int(usd_amount * (10 ** decimals))
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def parse_sui_amount(base_units: int, decimals: int = 6) -> float:
|
|
414
|
+
"""
|
|
415
|
+
Convert Sui token base units to USD amount.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
base_units: Amount in base units
|
|
419
|
+
decimals: Token decimals (6 for USDC)
|
|
420
|
+
|
|
421
|
+
Returns:
|
|
422
|
+
Amount in USD
|
|
423
|
+
"""
|
|
424
|
+
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.
|
|
4
|
-
Summary: Python SDK for x402 payments - gasless crypto payments across
|
|
3
|
+
Version: 0.5.5
|
|
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 **
|
|
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
|
-
- **
|
|
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=
|
|
1
|
+
uvd_x402_sdk/__init__.py,sha256=mn1GGLPDTxhjVvgJqp04z8lAnGdGoElPM0b64LAGBFk,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=
|
|
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=
|
|
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=
|
|
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
|
|
22
|
-
uvd_x402_sdk-0.5.
|
|
23
|
-
uvd_x402_sdk-0.5.
|
|
24
|
-
uvd_x402_sdk-0.5.
|
|
25
|
-
uvd_x402_sdk-0.5.
|
|
21
|
+
uvd_x402_sdk/networks/sui.py,sha256=vADFOC6Q8GcUWCjnx4f9C-uyegmR9uPlUiFRTQv_qJc,12578
|
|
22
|
+
uvd_x402_sdk-0.5.5.dist-info/LICENSE,sha256=OcLzB_iSgMbvk7b0dlyvleY_IbL2WUaPxvn1CHw2uAc,1073
|
|
23
|
+
uvd_x402_sdk-0.5.5.dist-info/METADATA,sha256=lyMKCBnLve4xUhk1MQQMEwvBZzPLQ1AX7wTKNgp1Jys,36537
|
|
24
|
+
uvd_x402_sdk-0.5.5.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
25
|
+
uvd_x402_sdk-0.5.5.dist-info/top_level.txt,sha256=Exyjj_Kl7CDAGFMi72lT9oFPOYiRNZb3l8tr906mMmc,13
|
|
26
|
+
uvd_x402_sdk-0.5.5.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|