uvd-x402-sdk 0.2.2__py3-none-any.whl → 0.3.0__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 +185 -169
- uvd_x402_sdk/client.py +527 -527
- uvd_x402_sdk/config.py +248 -248
- uvd_x402_sdk/decorators.py +325 -325
- uvd_x402_sdk/exceptions.py +254 -254
- uvd_x402_sdk/integrations/__init__.py +74 -74
- uvd_x402_sdk/integrations/django_integration.py +237 -237
- uvd_x402_sdk/integrations/fastapi_integration.py +330 -330
- uvd_x402_sdk/integrations/flask_integration.py +259 -259
- uvd_x402_sdk/integrations/lambda_integration.py +320 -320
- uvd_x402_sdk/models.py +397 -397
- uvd_x402_sdk/networks/__init__.py +80 -54
- uvd_x402_sdk/networks/base.py +498 -347
- uvd_x402_sdk/networks/evm.py +356 -215
- uvd_x402_sdk/networks/near.py +397 -397
- uvd_x402_sdk/networks/solana.py +282 -282
- uvd_x402_sdk/networks/stellar.py +129 -129
- uvd_x402_sdk/response.py +439 -439
- {uvd_x402_sdk-0.2.2.dist-info → uvd_x402_sdk-0.3.0.dist-info}/LICENSE +21 -21
- {uvd_x402_sdk-0.2.2.dist-info → uvd_x402_sdk-0.3.0.dist-info}/METADATA +927 -778
- uvd_x402_sdk-0.3.0.dist-info/RECORD +23 -0
- uvd_x402_sdk-0.2.2.dist-info/RECORD +0 -23
- {uvd_x402_sdk-0.2.2.dist-info → uvd_x402_sdk-0.3.0.dist-info}/WHEEL +0 -0
- {uvd_x402_sdk-0.2.2.dist-info → uvd_x402_sdk-0.3.0.dist-info}/top_level.txt +0 -0
uvd_x402_sdk/networks/solana.py
CHANGED
|
@@ -1,282 +1,282 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Solana Virtual Machine (SVM) network configurations.
|
|
3
|
-
|
|
4
|
-
This module supports all SVM-compatible chains:
|
|
5
|
-
- Solana (mainnet)
|
|
6
|
-
- Fogo (fast finality SVM)
|
|
7
|
-
|
|
8
|
-
All SVM chains use the same payment flow:
|
|
9
|
-
1. User creates a partially-signed VersionedTransaction
|
|
10
|
-
2. Transaction contains SPL token TransferChecked instruction
|
|
11
|
-
3. Facilitator is fee payer (user pays ZERO SOL/tokens)
|
|
12
|
-
4. Facilitator co-signs and submits transaction
|
|
13
|
-
|
|
14
|
-
Transaction Structure (flexible, facilitator v1.9.4+):
|
|
15
|
-
- SetComputeUnitLimit instruction (recommended: 20,000 units)
|
|
16
|
-
- SetComputeUnitPrice instruction (recommended: 100,000 microLamports)
|
|
17
|
-
- TransferChecked (USDC transfer)
|
|
18
|
-
- Optional: CreateAssociatedTokenAccount (if recipient ATA doesn't exist)
|
|
19
|
-
- Additional instructions may be added by wallets (e.g., Phantom memo)
|
|
20
|
-
|
|
21
|
-
The facilitator scans for the transfer instruction rather than requiring
|
|
22
|
-
fixed positions, allowing wallets like Phantom to add extra instructions.
|
|
23
|
-
The full signed transaction is sent to the facilitator, which uses it
|
|
24
|
-
exactly as signed (no reconstruction).
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
import base64
|
|
28
|
-
from typing import Dict, Any, Optional
|
|
29
|
-
|
|
30
|
-
from uvd_x402_sdk.networks.base import (
|
|
31
|
-
NetworkConfig,
|
|
32
|
-
NetworkType,
|
|
33
|
-
register_network,
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# =============================================================================
|
|
38
|
-
# SVM Networks Configuration
|
|
39
|
-
# =============================================================================
|
|
40
|
-
|
|
41
|
-
# Solana Mainnet
|
|
42
|
-
SOLANA = NetworkConfig(
|
|
43
|
-
name="solana",
|
|
44
|
-
display_name="Solana",
|
|
45
|
-
network_type=NetworkType.SVM, # Use SVM type for all Solana-compatible chains
|
|
46
|
-
chain_id=0, # Non-EVM, no chain ID
|
|
47
|
-
usdc_address="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", # USDC SPL token mint
|
|
48
|
-
usdc_decimals=6,
|
|
49
|
-
usdc_domain_name="", # Not applicable for SVM
|
|
50
|
-
usdc_domain_version="",
|
|
51
|
-
rpc_url="https://api.mainnet-beta.solana.com",
|
|
52
|
-
enabled=True,
|
|
53
|
-
extra_config={
|
|
54
|
-
# Token program ID (standard SPL token program)
|
|
55
|
-
"token_program_id": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
|
|
56
|
-
# Associated Token Account program
|
|
57
|
-
"ata_program_id": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
|
|
58
|
-
# Default compute units for transfer
|
|
59
|
-
"compute_units": 20000,
|
|
60
|
-
# Priority fee in microLamports (100k for fast landing on mainnet)
|
|
61
|
-
"priority_fee_microlamports": 100_000,
|
|
62
|
-
# Block explorer
|
|
63
|
-
"explorer_url": "https://solscan.io",
|
|
64
|
-
# Genesis hash (first 32 chars for CAIP-2)
|
|
65
|
-
"genesis_hash": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
66
|
-
# Network type identifier
|
|
67
|
-
"svm_network": "solana",
|
|
68
|
-
},
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
# Fogo (SVM chain with ultra-fast finality)
|
|
72
|
-
FOGO = NetworkConfig(
|
|
73
|
-
name="fogo",
|
|
74
|
-
display_name="Fogo",
|
|
75
|
-
network_type=NetworkType.SVM,
|
|
76
|
-
chain_id=0, # Non-EVM, no chain ID
|
|
77
|
-
usdc_address="uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG", # Fogo USDC mint
|
|
78
|
-
usdc_decimals=6,
|
|
79
|
-
usdc_domain_name="", # Not applicable for SVM
|
|
80
|
-
usdc_domain_version="",
|
|
81
|
-
rpc_url="https://rpc.fogo.nightly.app/",
|
|
82
|
-
enabled=True,
|
|
83
|
-
extra_config={
|
|
84
|
-
# Token program ID (standard SPL token program - same as Solana)
|
|
85
|
-
"token_program_id": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
|
|
86
|
-
# Associated Token Account program (same as Solana)
|
|
87
|
-
"ata_program_id": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
|
|
88
|
-
# Default compute units for transfer
|
|
89
|
-
"compute_units": 20000,
|
|
90
|
-
# Priority fee in microLamports (100k for fast landing)
|
|
91
|
-
"priority_fee_microlamports": 100_000,
|
|
92
|
-
# Block explorer (placeholder - update when available)
|
|
93
|
-
"explorer_url": "https://explorer.fogo.nightly.app",
|
|
94
|
-
# Network type identifier
|
|
95
|
-
"svm_network": "fogo",
|
|
96
|
-
# Fogo-specific: Ultra-fast finality (~400ms)
|
|
97
|
-
"finality_ms": 400,
|
|
98
|
-
},
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
# Register SVM networks
|
|
102
|
-
register_network(SOLANA)
|
|
103
|
-
register_network(FOGO)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
# =============================================================================
|
|
107
|
-
# SVM-specific utilities
|
|
108
|
-
# =============================================================================
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def is_svm_network(network_name: str) -> bool:
|
|
112
|
-
"""
|
|
113
|
-
Check if a network is SVM-compatible.
|
|
114
|
-
|
|
115
|
-
Args:
|
|
116
|
-
network_name: Network name to check
|
|
117
|
-
|
|
118
|
-
Returns:
|
|
119
|
-
True if network uses SVM (Solana, Fogo, etc.)
|
|
120
|
-
"""
|
|
121
|
-
from uvd_x402_sdk.networks.base import get_network, NetworkType
|
|
122
|
-
|
|
123
|
-
network = get_network(network_name)
|
|
124
|
-
if not network:
|
|
125
|
-
return False
|
|
126
|
-
return NetworkType.is_svm(network.network_type)
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def get_svm_networks() -> list:
|
|
130
|
-
"""
|
|
131
|
-
Get all registered SVM networks.
|
|
132
|
-
|
|
133
|
-
Returns:
|
|
134
|
-
List of SVM NetworkConfig instances
|
|
135
|
-
"""
|
|
136
|
-
from uvd_x402_sdk.networks.base import list_networks, NetworkType
|
|
137
|
-
|
|
138
|
-
return [
|
|
139
|
-
n for n in list_networks(enabled_only=True)
|
|
140
|
-
if NetworkType.is_svm(n.network_type)
|
|
141
|
-
]
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def get_associated_token_address(owner: str, mint: str) -> str:
|
|
145
|
-
"""
|
|
146
|
-
Derive the Associated Token Account (ATA) address for an owner and mint.
|
|
147
|
-
|
|
148
|
-
Note: This is a placeholder. For actual derivation, use the solana-py library:
|
|
149
|
-
|
|
150
|
-
from solders.pubkey import Pubkey
|
|
151
|
-
from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID
|
|
152
|
-
from spl.token.instructions import get_associated_token_address
|
|
153
|
-
|
|
154
|
-
Args:
|
|
155
|
-
owner: Owner's public key (base58)
|
|
156
|
-
mint: Token mint address (base58)
|
|
157
|
-
|
|
158
|
-
Returns:
|
|
159
|
-
Associated token account address (base58)
|
|
160
|
-
"""
|
|
161
|
-
# This would require solders/solana-py for actual implementation
|
|
162
|
-
# Returning empty string as placeholder
|
|
163
|
-
raise NotImplementedError(
|
|
164
|
-
"ATA derivation requires solana-py library. "
|
|
165
|
-
"Install with: pip install uvd-x402-sdk[solana]"
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def validate_svm_transaction_structure(transaction_base64: str) -> bool:
|
|
170
|
-
"""
|
|
171
|
-
Validate that an SVM transaction has the correct structure for x402.
|
|
172
|
-
|
|
173
|
-
The facilitator expects (flexible order, Dec 2024+):
|
|
174
|
-
- VersionedTransaction with at least 3 instructions
|
|
175
|
-
- SetComputeUnitLimit instruction (any position)
|
|
176
|
-
- SetComputeUnitPrice instruction (any position)
|
|
177
|
-
- TransferChecked instruction (SPL token)
|
|
178
|
-
- Optional: CreateAssociatedTokenAccount instruction
|
|
179
|
-
- Optional: Additional instructions from wallet (e.g., Phantom memo)
|
|
180
|
-
|
|
181
|
-
Note: Wallets like Phantom may add extra instructions during signing.
|
|
182
|
-
The facilitator v1.9.4+ handles this by scanning for the transfer
|
|
183
|
-
instruction rather than requiring fixed positions.
|
|
184
|
-
|
|
185
|
-
Args:
|
|
186
|
-
transaction_base64: Base64-encoded serialized transaction
|
|
187
|
-
|
|
188
|
-
Returns:
|
|
189
|
-
True if structure is valid
|
|
190
|
-
|
|
191
|
-
Raises:
|
|
192
|
-
ValueError: If structure is invalid
|
|
193
|
-
"""
|
|
194
|
-
try:
|
|
195
|
-
tx_bytes = base64.b64decode(transaction_base64)
|
|
196
|
-
except Exception as e:
|
|
197
|
-
raise ValueError(f"Invalid base64 transaction: {e}")
|
|
198
|
-
|
|
199
|
-
# Basic length validation
|
|
200
|
-
# Minimum: version (1) + header (3) + accounts array (varies) + blockhash (32) + instructions
|
|
201
|
-
if len(tx_bytes) < 50:
|
|
202
|
-
raise ValueError(f"Transaction too short: {len(tx_bytes)} bytes")
|
|
203
|
-
|
|
204
|
-
# Full validation requires solders/solana-py
|
|
205
|
-
# For now, we just check basic structure
|
|
206
|
-
return True
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
def validate_svm_payload(payload: Dict[str, Any]) -> bool:
|
|
210
|
-
"""
|
|
211
|
-
Validate an SVM payment payload structure.
|
|
212
|
-
|
|
213
|
-
The payload must contain a base64-encoded partially-signed transaction.
|
|
214
|
-
|
|
215
|
-
Args:
|
|
216
|
-
payload: Payload dictionary from x402 payment
|
|
217
|
-
|
|
218
|
-
Returns:
|
|
219
|
-
True if valid, raises ValueError if invalid
|
|
220
|
-
"""
|
|
221
|
-
if "transaction" not in payload:
|
|
222
|
-
raise ValueError("SVM payload missing 'transaction' field")
|
|
223
|
-
|
|
224
|
-
transaction_b64 = payload["transaction"]
|
|
225
|
-
|
|
226
|
-
try:
|
|
227
|
-
tx_bytes = base64.b64decode(transaction_b64)
|
|
228
|
-
except Exception as e:
|
|
229
|
-
raise ValueError(f"Invalid base64 in transaction: {e}")
|
|
230
|
-
|
|
231
|
-
# Basic length validation
|
|
232
|
-
if len(tx_bytes) < 50:
|
|
233
|
-
raise ValueError(f"Transaction too short: {len(tx_bytes)} bytes")
|
|
234
|
-
|
|
235
|
-
return True
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def is_valid_solana_address(address: str) -> bool:
|
|
239
|
-
"""
|
|
240
|
-
Validate a Solana/SVM public key format.
|
|
241
|
-
|
|
242
|
-
Solana addresses are base58-encoded 32-byte public keys.
|
|
243
|
-
|
|
244
|
-
Args:
|
|
245
|
-
address: Address to validate
|
|
246
|
-
|
|
247
|
-
Returns:
|
|
248
|
-
True if valid base58 address
|
|
249
|
-
"""
|
|
250
|
-
if not address or not isinstance(address, str):
|
|
251
|
-
return False
|
|
252
|
-
|
|
253
|
-
# Base58 alphabet (no 0, O, I, l)
|
|
254
|
-
base58_alphabet = set("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
|
|
255
|
-
|
|
256
|
-
if not all(c in base58_alphabet for c in address):
|
|
257
|
-
return False
|
|
258
|
-
|
|
259
|
-
# Typical Solana address length is 32-44 characters
|
|
260
|
-
return 32 <= len(address) <= 44
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
# =============================================================================
|
|
264
|
-
# Transaction Building Utilities (for reference)
|
|
265
|
-
# =============================================================================
|
|
266
|
-
|
|
267
|
-
# These constants are useful for building transactions programmatically
|
|
268
|
-
|
|
269
|
-
# Compute Budget Program
|
|
270
|
-
COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111"
|
|
271
|
-
|
|
272
|
-
# SetComputeUnitLimit instruction discriminator
|
|
273
|
-
SET_COMPUTE_UNIT_LIMIT_DISCRIMINATOR = 2
|
|
274
|
-
|
|
275
|
-
# SetComputeUnitPrice instruction discriminator
|
|
276
|
-
SET_COMPUTE_UNIT_PRICE_DISCRIMINATOR = 3
|
|
277
|
-
|
|
278
|
-
# Default values for x402 transactions
|
|
279
|
-
DEFAULT_COMPUTE_UNITS = 20000
|
|
280
|
-
# Use 100k microlamports/CU for fast landing on mainnet
|
|
281
|
-
# Lower values (like 1) cause transactions to be deprioritized and time out
|
|
282
|
-
DEFAULT_PRIORITY_FEE_MICROLAMPORTS = 100_000
|
|
1
|
+
"""
|
|
2
|
+
Solana Virtual Machine (SVM) network configurations.
|
|
3
|
+
|
|
4
|
+
This module supports all SVM-compatible chains:
|
|
5
|
+
- Solana (mainnet)
|
|
6
|
+
- Fogo (fast finality SVM)
|
|
7
|
+
|
|
8
|
+
All SVM chains use the same payment flow:
|
|
9
|
+
1. User creates a partially-signed VersionedTransaction
|
|
10
|
+
2. Transaction contains SPL token TransferChecked instruction
|
|
11
|
+
3. Facilitator is fee payer (user pays ZERO SOL/tokens)
|
|
12
|
+
4. Facilitator co-signs and submits transaction
|
|
13
|
+
|
|
14
|
+
Transaction Structure (flexible, facilitator v1.9.4+):
|
|
15
|
+
- SetComputeUnitLimit instruction (recommended: 20,000 units)
|
|
16
|
+
- SetComputeUnitPrice instruction (recommended: 100,000 microLamports)
|
|
17
|
+
- TransferChecked (USDC transfer)
|
|
18
|
+
- Optional: CreateAssociatedTokenAccount (if recipient ATA doesn't exist)
|
|
19
|
+
- Additional instructions may be added by wallets (e.g., Phantom memo)
|
|
20
|
+
|
|
21
|
+
The facilitator scans for the transfer instruction rather than requiring
|
|
22
|
+
fixed positions, allowing wallets like Phantom to add extra instructions.
|
|
23
|
+
The full signed transaction is sent to the facilitator, which uses it
|
|
24
|
+
exactly as signed (no reconstruction).
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import base64
|
|
28
|
+
from typing import Dict, Any, Optional
|
|
29
|
+
|
|
30
|
+
from uvd_x402_sdk.networks.base import (
|
|
31
|
+
NetworkConfig,
|
|
32
|
+
NetworkType,
|
|
33
|
+
register_network,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# =============================================================================
|
|
38
|
+
# SVM Networks Configuration
|
|
39
|
+
# =============================================================================
|
|
40
|
+
|
|
41
|
+
# Solana Mainnet
|
|
42
|
+
SOLANA = NetworkConfig(
|
|
43
|
+
name="solana",
|
|
44
|
+
display_name="Solana",
|
|
45
|
+
network_type=NetworkType.SVM, # Use SVM type for all Solana-compatible chains
|
|
46
|
+
chain_id=0, # Non-EVM, no chain ID
|
|
47
|
+
usdc_address="EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", # USDC SPL token mint
|
|
48
|
+
usdc_decimals=6,
|
|
49
|
+
usdc_domain_name="", # Not applicable for SVM
|
|
50
|
+
usdc_domain_version="",
|
|
51
|
+
rpc_url="https://api.mainnet-beta.solana.com",
|
|
52
|
+
enabled=True,
|
|
53
|
+
extra_config={
|
|
54
|
+
# Token program ID (standard SPL token program)
|
|
55
|
+
"token_program_id": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
|
|
56
|
+
# Associated Token Account program
|
|
57
|
+
"ata_program_id": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
|
|
58
|
+
# Default compute units for transfer
|
|
59
|
+
"compute_units": 20000,
|
|
60
|
+
# Priority fee in microLamports (100k for fast landing on mainnet)
|
|
61
|
+
"priority_fee_microlamports": 100_000,
|
|
62
|
+
# Block explorer
|
|
63
|
+
"explorer_url": "https://solscan.io",
|
|
64
|
+
# Genesis hash (first 32 chars for CAIP-2)
|
|
65
|
+
"genesis_hash": "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
66
|
+
# Network type identifier
|
|
67
|
+
"svm_network": "solana",
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# Fogo (SVM chain with ultra-fast finality)
|
|
72
|
+
FOGO = NetworkConfig(
|
|
73
|
+
name="fogo",
|
|
74
|
+
display_name="Fogo",
|
|
75
|
+
network_type=NetworkType.SVM,
|
|
76
|
+
chain_id=0, # Non-EVM, no chain ID
|
|
77
|
+
usdc_address="uSd2czE61Evaf76RNbq4KPpXnkiL3irdzgLFUMe3NoG", # Fogo USDC mint
|
|
78
|
+
usdc_decimals=6,
|
|
79
|
+
usdc_domain_name="", # Not applicable for SVM
|
|
80
|
+
usdc_domain_version="",
|
|
81
|
+
rpc_url="https://rpc.fogo.nightly.app/",
|
|
82
|
+
enabled=True,
|
|
83
|
+
extra_config={
|
|
84
|
+
# Token program ID (standard SPL token program - same as Solana)
|
|
85
|
+
"token_program_id": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
|
|
86
|
+
# Associated Token Account program (same as Solana)
|
|
87
|
+
"ata_program_id": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
|
|
88
|
+
# Default compute units for transfer
|
|
89
|
+
"compute_units": 20000,
|
|
90
|
+
# Priority fee in microLamports (100k for fast landing)
|
|
91
|
+
"priority_fee_microlamports": 100_000,
|
|
92
|
+
# Block explorer (placeholder - update when available)
|
|
93
|
+
"explorer_url": "https://explorer.fogo.nightly.app",
|
|
94
|
+
# Network type identifier
|
|
95
|
+
"svm_network": "fogo",
|
|
96
|
+
# Fogo-specific: Ultra-fast finality (~400ms)
|
|
97
|
+
"finality_ms": 400,
|
|
98
|
+
},
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
# Register SVM networks
|
|
102
|
+
register_network(SOLANA)
|
|
103
|
+
register_network(FOGO)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# =============================================================================
|
|
107
|
+
# SVM-specific utilities
|
|
108
|
+
# =============================================================================
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def is_svm_network(network_name: str) -> bool:
|
|
112
|
+
"""
|
|
113
|
+
Check if a network is SVM-compatible.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
network_name: Network name to check
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
True if network uses SVM (Solana, Fogo, etc.)
|
|
120
|
+
"""
|
|
121
|
+
from uvd_x402_sdk.networks.base import get_network, NetworkType
|
|
122
|
+
|
|
123
|
+
network = get_network(network_name)
|
|
124
|
+
if not network:
|
|
125
|
+
return False
|
|
126
|
+
return NetworkType.is_svm(network.network_type)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def get_svm_networks() -> list:
|
|
130
|
+
"""
|
|
131
|
+
Get all registered SVM networks.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
List of SVM NetworkConfig instances
|
|
135
|
+
"""
|
|
136
|
+
from uvd_x402_sdk.networks.base import list_networks, NetworkType
|
|
137
|
+
|
|
138
|
+
return [
|
|
139
|
+
n for n in list_networks(enabled_only=True)
|
|
140
|
+
if NetworkType.is_svm(n.network_type)
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def get_associated_token_address(owner: str, mint: str) -> str:
|
|
145
|
+
"""
|
|
146
|
+
Derive the Associated Token Account (ATA) address for an owner and mint.
|
|
147
|
+
|
|
148
|
+
Note: This is a placeholder. For actual derivation, use the solana-py library:
|
|
149
|
+
|
|
150
|
+
from solders.pubkey import Pubkey
|
|
151
|
+
from spl.token.constants import TOKEN_PROGRAM_ID, ASSOCIATED_TOKEN_PROGRAM_ID
|
|
152
|
+
from spl.token.instructions import get_associated_token_address
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
owner: Owner's public key (base58)
|
|
156
|
+
mint: Token mint address (base58)
|
|
157
|
+
|
|
158
|
+
Returns:
|
|
159
|
+
Associated token account address (base58)
|
|
160
|
+
"""
|
|
161
|
+
# This would require solders/solana-py for actual implementation
|
|
162
|
+
# Returning empty string as placeholder
|
|
163
|
+
raise NotImplementedError(
|
|
164
|
+
"ATA derivation requires solana-py library. "
|
|
165
|
+
"Install with: pip install uvd-x402-sdk[solana]"
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def validate_svm_transaction_structure(transaction_base64: str) -> bool:
|
|
170
|
+
"""
|
|
171
|
+
Validate that an SVM transaction has the correct structure for x402.
|
|
172
|
+
|
|
173
|
+
The facilitator expects (flexible order, Dec 2024+):
|
|
174
|
+
- VersionedTransaction with at least 3 instructions
|
|
175
|
+
- SetComputeUnitLimit instruction (any position)
|
|
176
|
+
- SetComputeUnitPrice instruction (any position)
|
|
177
|
+
- TransferChecked instruction (SPL token)
|
|
178
|
+
- Optional: CreateAssociatedTokenAccount instruction
|
|
179
|
+
- Optional: Additional instructions from wallet (e.g., Phantom memo)
|
|
180
|
+
|
|
181
|
+
Note: Wallets like Phantom may add extra instructions during signing.
|
|
182
|
+
The facilitator v1.9.4+ handles this by scanning for the transfer
|
|
183
|
+
instruction rather than requiring fixed positions.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
transaction_base64: Base64-encoded serialized transaction
|
|
187
|
+
|
|
188
|
+
Returns:
|
|
189
|
+
True if structure is valid
|
|
190
|
+
|
|
191
|
+
Raises:
|
|
192
|
+
ValueError: If structure is invalid
|
|
193
|
+
"""
|
|
194
|
+
try:
|
|
195
|
+
tx_bytes = base64.b64decode(transaction_base64)
|
|
196
|
+
except Exception as e:
|
|
197
|
+
raise ValueError(f"Invalid base64 transaction: {e}")
|
|
198
|
+
|
|
199
|
+
# Basic length validation
|
|
200
|
+
# Minimum: version (1) + header (3) + accounts array (varies) + blockhash (32) + instructions
|
|
201
|
+
if len(tx_bytes) < 50:
|
|
202
|
+
raise ValueError(f"Transaction too short: {len(tx_bytes)} bytes")
|
|
203
|
+
|
|
204
|
+
# Full validation requires solders/solana-py
|
|
205
|
+
# For now, we just check basic structure
|
|
206
|
+
return True
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def validate_svm_payload(payload: Dict[str, Any]) -> bool:
|
|
210
|
+
"""
|
|
211
|
+
Validate an SVM payment payload structure.
|
|
212
|
+
|
|
213
|
+
The payload must contain a base64-encoded partially-signed transaction.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
payload: Payload dictionary from x402 payment
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
True if valid, raises ValueError if invalid
|
|
220
|
+
"""
|
|
221
|
+
if "transaction" not in payload:
|
|
222
|
+
raise ValueError("SVM payload missing 'transaction' field")
|
|
223
|
+
|
|
224
|
+
transaction_b64 = payload["transaction"]
|
|
225
|
+
|
|
226
|
+
try:
|
|
227
|
+
tx_bytes = base64.b64decode(transaction_b64)
|
|
228
|
+
except Exception as e:
|
|
229
|
+
raise ValueError(f"Invalid base64 in transaction: {e}")
|
|
230
|
+
|
|
231
|
+
# Basic length validation
|
|
232
|
+
if len(tx_bytes) < 50:
|
|
233
|
+
raise ValueError(f"Transaction too short: {len(tx_bytes)} bytes")
|
|
234
|
+
|
|
235
|
+
return True
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def is_valid_solana_address(address: str) -> bool:
|
|
239
|
+
"""
|
|
240
|
+
Validate a Solana/SVM public key format.
|
|
241
|
+
|
|
242
|
+
Solana addresses are base58-encoded 32-byte public keys.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
address: Address to validate
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
True if valid base58 address
|
|
249
|
+
"""
|
|
250
|
+
if not address or not isinstance(address, str):
|
|
251
|
+
return False
|
|
252
|
+
|
|
253
|
+
# Base58 alphabet (no 0, O, I, l)
|
|
254
|
+
base58_alphabet = set("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
|
|
255
|
+
|
|
256
|
+
if not all(c in base58_alphabet for c in address):
|
|
257
|
+
return False
|
|
258
|
+
|
|
259
|
+
# Typical Solana address length is 32-44 characters
|
|
260
|
+
return 32 <= len(address) <= 44
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
# =============================================================================
|
|
264
|
+
# Transaction Building Utilities (for reference)
|
|
265
|
+
# =============================================================================
|
|
266
|
+
|
|
267
|
+
# These constants are useful for building transactions programmatically
|
|
268
|
+
|
|
269
|
+
# Compute Budget Program
|
|
270
|
+
COMPUTE_BUDGET_PROGRAM_ID = "ComputeBudget111111111111111111111111111111"
|
|
271
|
+
|
|
272
|
+
# SetComputeUnitLimit instruction discriminator
|
|
273
|
+
SET_COMPUTE_UNIT_LIMIT_DISCRIMINATOR = 2
|
|
274
|
+
|
|
275
|
+
# SetComputeUnitPrice instruction discriminator
|
|
276
|
+
SET_COMPUTE_UNIT_PRICE_DISCRIMINATOR = 3
|
|
277
|
+
|
|
278
|
+
# Default values for x402 transactions
|
|
279
|
+
DEFAULT_COMPUTE_UNITS = 20000
|
|
280
|
+
# Use 100k microlamports/CU for fast landing on mainnet
|
|
281
|
+
# Lower values (like 1) cause transactions to be deprioritized and time out
|
|
282
|
+
DEFAULT_PRIORITY_FEE_MICROLAMPORTS = 100_000
|