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.
@@ -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