chipi-stack 2.0.0__tar.gz → 2.2.0__tar.gz

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.
Files changed (55) hide show
  1. {chipi_stack-2.0.0/chipi_stack.egg-info → chipi_stack-2.2.0}/PKG-INFO +32 -5
  2. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/README.md +27 -3
  3. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/__init__.py +24 -1
  4. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/constants.py +80 -3
  5. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/execute_paymaster.py +128 -6
  6. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/__init__.py +2 -0
  7. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/core.py +6 -0
  8. chipi_stack-2.2.0/chipi_sdk/models/sku_purchase.py +40 -0
  9. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/wallet.py +58 -5
  10. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/sdk.py +59 -0
  11. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/sessions.py +57 -24
  12. chipi_stack-2.2.0/chipi_sdk/shhh/__init__.py +249 -0
  13. chipi_stack-2.2.0/chipi_sdk/shhh/compute_wallet_address.py +97 -0
  14. chipi_stack-2.2.0/chipi_sdk/shhh/execute_paymaster_raw.py +439 -0
  15. chipi_stack-2.2.0/chipi_sdk/shhh/migrate.py +358 -0
  16. chipi_stack-2.2.0/chipi_sdk/shhh/oe.py +189 -0
  17. chipi_stack-2.2.0/chipi_sdk/shhh/recovery.py +450 -0
  18. chipi_stack-2.2.0/chipi_sdk/shhh/signers/__init__.py +77 -0
  19. chipi_stack-2.2.0/chipi_sdk/shhh/signers/ed25519.py +157 -0
  20. chipi_stack-2.2.0/chipi_sdk/shhh/signers/eip191.py +261 -0
  21. chipi_stack-2.2.0/chipi_sdk/shhh/signers/jwt_apple_sub.py +517 -0
  22. chipi_stack-2.2.0/chipi_sdk/shhh/signers/stark.py +92 -0
  23. chipi_stack-2.2.0/chipi_sdk/shhh/snip12_hash.py +214 -0
  24. chipi_stack-2.2.0/chipi_sdk/shhh/threshold.py +295 -0
  25. chipi_stack-2.2.0/chipi_sdk/sku_purchases.py +98 -0
  26. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/wallets.py +223 -49
  27. {chipi_stack-2.0.0 → chipi_stack-2.2.0/chipi_stack.egg-info}/PKG-INFO +32 -5
  28. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_stack.egg-info/SOURCES.txt +15 -0
  29. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_stack.egg-info/requires.txt +4 -1
  30. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/pyproject.toml +10 -2
  31. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/LICENSE +0 -0
  32. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/MANIFEST.in +0 -0
  33. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/client.py +0 -0
  34. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/encryption.py +0 -0
  35. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/errors.py +0 -0
  36. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/formatters.py +0 -0
  37. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/session.py +0 -0
  38. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/sku.py +0 -0
  39. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/sku_transaction.py +0 -0
  40. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/transaction.py +0 -0
  41. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/user.py +0 -0
  42. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/x402.py +0 -0
  43. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/py.typed +0 -0
  44. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/sku_transactions.py +0 -0
  45. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/skus.py +0 -0
  46. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/transactions.py +0 -0
  47. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/users.py +0 -0
  48. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/validators.py +0 -0
  49. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/x402_client.py +0 -0
  50. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/x402_facilitator.py +0 -0
  51. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/x402_middleware.py +0 -0
  52. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_stack.egg-info/dependency_links.txt +0 -0
  53. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_stack.egg-info/top_level.txt +0 -0
  54. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/setup.cfg +0 -0
  55. {chipi_stack-2.0.0 → chipi_stack-2.2.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chipi-stack
3
- Version: 2.0.0
3
+ Version: 2.2.0
4
4
  Summary: Python SDK for Starknet Gasless Transactions via Chipi
5
5
  Author-email: Carlos Castillo <carlos@chipipay.com>, Roberto Yamanaka <roberto@chipipay.com>
6
6
  License-Expression: MIT
@@ -25,6 +25,10 @@ Requires-Dist: pydantic>=2.0.0
25
25
  Requires-Dist: httpx>=0.27.0
26
26
  Requires-Dist: cryptography>=42.0.0
27
27
  Requires-Dist: typing-extensions>=4.9.0
28
+ Requires-Dist: poseidon-py>=0.1.5
29
+ Requires-Dist: pycryptodome>=3.20.0
30
+ Requires-Dist: garaga==1.1.0
31
+ Requires-Dist: eth-keys>=0.5.0
28
32
  Provides-Extra: dev
29
33
  Requires-Dist: pytest>=8.0.0; extra == "dev"
30
34
  Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
@@ -34,17 +38,18 @@ Requires-Dist: black>=24.0.0; extra == "dev"
34
38
  Requires-Dist: ruff>=0.3.0; extra == "dev"
35
39
  Requires-Dist: mypy>=1.8.0; extra == "dev"
36
40
  Requires-Dist: build>=1.0.0; extra == "dev"
37
- Requires-Dist: twine>=5.0.0; extra == "dev"
38
41
  Dynamic: license-file
39
42
 
40
43
  # Chipi Python SDK
41
44
 
42
- [![PyPI version](https://badge.fury.io/py/chipi-python.svg)](https://badge.fury.io/py/chipi-python)
45
+ [![PyPI version](https://badge.fury.io/py/chipi-stack.svg)](https://badge.fury.io/py/chipi-stack)
43
46
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
44
47
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
45
48
 
46
49
  Python SDK for executing gasless transactions on Starknet via Chipi's paymaster infrastructure.
47
50
 
51
+ > Published to PyPI as **`chipi-stack`** — matches the `@chipi-stack/*` npm scope. The legacy `chipi-python` package on PyPI is deprecated.
52
+
48
53
  ## Features
49
54
 
50
55
  - 🚀 **Gasless Transactions** - Execute transactions without paying gas fees
@@ -57,13 +62,13 @@ Python SDK for executing gasless transactions on Starknet via Chipi's paymaster
57
62
  ## Installation
58
63
 
59
64
  ```bash
60
- pip install chipi-python
65
+ pip install chipi-stack
61
66
  ```
62
67
 
63
68
  Or with uv:
64
69
 
65
70
  ```bash
66
- uv add chipi-python
71
+ uv add chipi-stack
67
72
  ```
68
73
 
69
74
  ### Requirements
@@ -74,6 +79,28 @@ uv add chipi-python
74
79
  - `pydantic>=2.0.0` - Data validation
75
80
  - `httpx>=0.27.0` - HTTP client
76
81
  - `cryptography>=42.0.0` - AES encryption
82
+ - `garaga==1.1.0` - Cairo-compatible BN-curve math for SHHH Ed25519 signing
83
+ - `eth-keys>=0.5.0` - secp256k1 ECDSA for SHHH EIP-191 signing
84
+ - `poseidon-py>=0.1.5` - Poseidon hash (used by SHHH SNIP-12 envelopes)
85
+ - `pycryptodome>=3.20.0` - keccak256 (used by SHHH EIP-191)
86
+
87
+ ### macOS Apple Silicon installation note
88
+
89
+ Garaga's BN-curve math links against libssl. On macOS 14 Sonoma+ on
90
+ Apple Silicon, the system libssl can mis-link during the garaga build.
91
+ If `pip install chipi-stack` fails with "library not loaded" or
92
+ "Symbol not found" mentioning `libssl` / `libcrypto`, install OpenSSL 3
93
+ via Homebrew and re-install:
94
+
95
+ ```bash
96
+ brew install openssl@3
97
+ export LDFLAGS="-L$(brew --prefix openssl@3)/lib"
98
+ export CPPFLAGS="-I$(brew --prefix openssl@3)/include"
99
+ pip install --force-reinstall chipi-stack
100
+ ```
101
+
102
+ Linux and Intel Macs are unaffected. Windows is untested for the SHHH
103
+ Ed25519 signer specifically; the rest of the SDK works on Windows.
77
104
 
78
105
  ## Quick Start
79
106
 
@@ -1,11 +1,13 @@
1
1
  # Chipi Python SDK
2
2
 
3
- [![PyPI version](https://badge.fury.io/py/chipi-python.svg)](https://badge.fury.io/py/chipi-python)
3
+ [![PyPI version](https://badge.fury.io/py/chipi-stack.svg)](https://badge.fury.io/py/chipi-stack)
4
4
  [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
5
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
6
 
7
7
  Python SDK for executing gasless transactions on Starknet via Chipi's paymaster infrastructure.
8
8
 
9
+ > Published to PyPI as **`chipi-stack`** — matches the `@chipi-stack/*` npm scope. The legacy `chipi-python` package on PyPI is deprecated.
10
+
9
11
  ## Features
10
12
 
11
13
  - 🚀 **Gasless Transactions** - Execute transactions without paying gas fees
@@ -18,13 +20,13 @@ Python SDK for executing gasless transactions on Starknet via Chipi's paymaster
18
20
  ## Installation
19
21
 
20
22
  ```bash
21
- pip install chipi-python
23
+ pip install chipi-stack
22
24
  ```
23
25
 
24
26
  Or with uv:
25
27
 
26
28
  ```bash
27
- uv add chipi-python
29
+ uv add chipi-stack
28
30
  ```
29
31
 
30
32
  ### Requirements
@@ -35,6 +37,28 @@ uv add chipi-python
35
37
  - `pydantic>=2.0.0` - Data validation
36
38
  - `httpx>=0.27.0` - HTTP client
37
39
  - `cryptography>=42.0.0` - AES encryption
40
+ - `garaga==1.1.0` - Cairo-compatible BN-curve math for SHHH Ed25519 signing
41
+ - `eth-keys>=0.5.0` - secp256k1 ECDSA for SHHH EIP-191 signing
42
+ - `poseidon-py>=0.1.5` - Poseidon hash (used by SHHH SNIP-12 envelopes)
43
+ - `pycryptodome>=3.20.0` - keccak256 (used by SHHH EIP-191)
44
+
45
+ ### macOS Apple Silicon installation note
46
+
47
+ Garaga's BN-curve math links against libssl. On macOS 14 Sonoma+ on
48
+ Apple Silicon, the system libssl can mis-link during the garaga build.
49
+ If `pip install chipi-stack` fails with "library not loaded" or
50
+ "Symbol not found" mentioning `libssl` / `libcrypto`, install OpenSSL 3
51
+ via Homebrew and re-install:
52
+
53
+ ```bash
54
+ brew install openssl@3
55
+ export LDFLAGS="-L$(brew --prefix openssl@3)/lib"
56
+ export CPPFLAGS="-I$(brew --prefix openssl@3)/include"
57
+ pip install --force-reinstall chipi-stack
58
+ ```
59
+
60
+ Linux and Intel Macs are unaffected. Windows is untested for the SHHH
61
+ Ed25519 signer specifically; the rest of the SDK works on Windows.
38
62
 
39
63
  ## Quick Start
40
64
 
@@ -5,7 +5,7 @@ A Python SDK for interacting with Chipi's gasless transaction infrastructure on
5
5
  Supports wallet creation, transaction execution, session keys, and more.
6
6
  """
7
7
 
8
- __version__ = "2.0.0"
8
+ __version__ = "2.1.0"
9
9
 
10
10
  # Main SDK class
11
11
  from .sdk import ChipiSDK
@@ -19,6 +19,7 @@ from .transactions import ChipiTransactions
19
19
  from .sessions import ChipiSessions
20
20
  from .skus import ChipiSkus
21
21
  from .sku_transactions import ChipiSkuTransactions
22
+ from .sku_purchases import ChipiSkuPurchases
22
23
  from .users import ChipiUsers
23
24
 
24
25
  # Models - Core
@@ -26,6 +27,7 @@ from .models.core import (
26
27
  Chain,
27
28
  ChainToken,
28
29
  ChipiSDKConfig,
30
+ Currency,
29
31
  PaginatedResponse,
30
32
  PaginationQuery,
31
33
  StarknetContract,
@@ -44,6 +46,7 @@ from .models.wallet import (
44
46
  GetWalletResponse,
45
47
  PasskeyMetadata,
46
48
  PrepareWalletCreationResponse,
49
+ ShhhSignerKind,
47
50
  WalletData,
48
51
  WalletType,
49
52
  PrepareWalletUpgradeParams,
@@ -103,6 +106,11 @@ from .models.sku_transaction import (
103
106
  SkuTransaction,
104
107
  )
105
108
 
109
+ # Models - SKU Purchase (bill payments)
110
+ from .models.sku_purchase import (
111
+ CreateSkuPurchaseParams,
112
+ )
113
+
106
114
  # Models - User
107
115
  from .models.user import (
108
116
  CreateUserParams,
@@ -156,17 +164,22 @@ from .constants import (
156
164
  DEFAULT_PAGINATION,
157
165
  ERRORS,
158
166
  LEGACY_CHIPI_CLASS_HASHES,
167
+ LEGACY_SHHH_CLASS_HASHES,
159
168
  PAYMASTER_CONFIG,
160
169
  SERVICE_TYPES,
161
170
  SESSION_DEFAULTS,
162
171
  SESSION_ENTRYPOINTS,
163
172
  SESSION_ERRORS,
173
+ SHHH_ENVELOPE_TAGS,
174
+ SHHH_KIND_GAS_OVERHEAD,
175
+ SHHH_VERIFIER_CLASS_HASHES,
164
176
  SKU_CONTRACTS,
165
177
  STARKNET_NETWORKS,
166
178
  TOKEN_DECIMALS,
167
179
  WALLET_CLASS_HASHES,
168
180
  WALLET_RPC_ENDPOINTS,
169
181
  get_wallet_type_from_class_hash,
182
+ is_known_shhh_class_hash,
170
183
  )
171
184
 
172
185
  # Utilities
@@ -205,11 +218,13 @@ __all__ = [
205
218
  "ChipiSessions",
206
219
  "ChipiSkus",
207
220
  "ChipiSkuTransactions",
221
+ "ChipiSkuPurchases",
208
222
  "ChipiUsers",
209
223
  # Core models
210
224
  "Chain",
211
225
  "ChainToken",
212
226
  "ChipiSDKConfig",
227
+ "Currency",
213
228
  "PaginatedResponse",
214
229
  "PaginationQuery",
215
230
  "StarknetContract",
@@ -227,6 +242,7 @@ __all__ = [
227
242
  "PrepareWalletCreationResponse",
228
243
  "WalletData",
229
244
  "WalletType",
245
+ "ShhhSignerKind",
230
246
  "PrepareWalletUpgradeParams",
231
247
  "PrepareWalletUpgradeResponse",
232
248
  "ExecuteWalletUpgradeParams",
@@ -270,6 +286,8 @@ __all__ = [
270
286
  # SKU Transaction models
271
287
  "CreateSkuTransactionParams",
272
288
  "SkuTransaction",
289
+ # SKU Purchase models (bill payments)
290
+ "CreateSkuPurchaseParams",
273
291
  # User models
274
292
  "CreateUserParams",
275
293
  "GetUserParams",
@@ -308,7 +326,12 @@ __all__ = [
308
326
  "TOKEN_DECIMALS",
309
327
  "WALLET_CLASS_HASHES",
310
328
  "LEGACY_CHIPI_CLASS_HASHES",
329
+ "LEGACY_SHHH_CLASS_HASHES",
330
+ "SHHH_ENVELOPE_TAGS",
331
+ "SHHH_KIND_GAS_OVERHEAD",
332
+ "SHHH_VERIFIER_CLASS_HASHES",
311
333
  "get_wallet_type_from_class_hash",
334
+ "is_known_shhh_class_hash",
312
335
  "WALLET_RPC_ENDPOINTS",
313
336
  # Utilities
314
337
  "camel_to_snake",
@@ -1,7 +1,7 @@
1
1
  """Constants used across Chipi SDK."""
2
2
 
3
3
  from typing import Optional
4
- from .models.wallet import WalletType
4
+ from .models.wallet import ShhhSignerKind, WalletType
5
5
 
6
6
 
7
7
  # API Versioning
@@ -35,7 +35,8 @@ API_ENDPOINTS = {
35
35
  "CHIPI_WALLETS": "/chipi-wallets",
36
36
  "TRANSACTIONS": "/transactions",
37
37
  "SKUS": "/skus",
38
- "SKU_TRANSACTIONS": "/sku-transactions",
38
+ "SKU_PURCHASES": "/sku-purchases",
39
+ "SKU_TRANSACTIONS": "/sku-transactions", # legacy / deprecated — see purchase_sku
39
40
  "EXCHANGES": "/exchanges",
40
41
  "USERS": "/users",
41
42
  }
@@ -94,6 +95,7 @@ CHAIN_TOKEN_TYPES = {
94
95
  WALLET_CLASS_HASHES: dict[WalletType, str] = {
95
96
  WalletType.CHIPI: "0x0484bbd2404b3c7264bea271f7267d6d4004821ac7787a9eed7f472e79ef40d1", # v33 — latest, spending policy + audit fixes
96
97
  WalletType.READY: "0x036078334509b514626504edc9fb252328d1a240e4e948bef8d0c08dff45927f",
98
+ WalletType.SHHH: "0x075dfb396145926bffa6beb659897f46cc082a50b211d80871cff7f1038fa58a", # V8.4 ShhhAccount — declared 2026-05-15, audit-closed
97
99
  }
98
100
 
99
101
  # Previous CHIPI wallet class hashes still deployed on-chain (newest → oldest)
@@ -105,6 +107,54 @@ LEGACY_CHIPI_CLASS_HASHES: list[str] = [
105
107
  "0x02de1565226d5215a38b68c4d9a4913989b54edff64c68c45e453c417b44cd83", # v28
106
108
  ]
107
109
 
110
+ # Deprecated SHHH class hashes still deployed on-chain. V8 series ships
111
+ # without an `upgrade` selector, so existing instances at deprecated classes
112
+ # cannot self-upgrade — they redeploy at the current SHHH class hash.
113
+ LEGACY_SHHH_CLASS_HASHES: list[str] = [
114
+ "0x03bc539295abd3e59bd9ea799d12fe3331748d484bc77bff45b302b1636a87d9", # V8.3 — deprecated 2026-05-15
115
+ ]
116
+
117
+ # SHHH ShhhAccount verifier class hashes (V8.4, mainnet).
118
+ # Account dispatches `verify` to one of these via library_call_syscall based
119
+ # on the owner's `kind_tag`. Chipi routes as consumer; we do not redeclare.
120
+ SHHH_VERIFIER_CLASS_HASHES: dict[ShhhSignerKind, str] = {
121
+ ShhhSignerKind.STARK: "0x00d09209b2da9d49fc805ba26380ba4ce25aa641116c10eb178e1051a71dbf68",
122
+ ShhhSignerKind.ED25519: "0x030a7dfc03e59cef6e41699e734abd2df53ce393a052221c02c6e07665949f74",
123
+ ShhhSignerKind.SECP256K1: "0x03e81667a46bd5287e09a9600fa98d28fdc477735f2689f5f4e8e95f37b67b74",
124
+ ShhhSignerKind.EIP191_SECP256K1: "0x03a75997862059c36cb8e204fb3027eb6d1fdf933488d42c2db4528118d084e6",
125
+ ShhhSignerKind.EIP712_SECP256K1: "0x072a3f77e8c28bfea2ade91ec3fb83b6290169d1ed8c1b2396704231841c6474",
126
+ ShhhSignerKind.P256: "0x01b600709af54c8838e5f18ddad3a26feeb47cb124c239f55a0f1b7a780e2d8a",
127
+ ShhhSignerKind.WEBAUTHN_P256: "0x074f6efd2af9025cd8cab41a4565bc73b6ef097214c31352838fcdbac0a44657",
128
+ ShhhSignerKind.JWT_ES256: "0x002efce875fa3e73e04d825d8ebade53e188cc995dfe0c55a6a2f7fa6c59f497",
129
+ ShhhSignerKind.JWT_ES256_APPLE_SUB: "0x06b67762218a25fdd28e25b063480893a5cef9cdeecbc663e32d444d5734c471",
130
+ ShhhSignerKind.BLS12_381: "0x02623721e74a9ad3e0ba639065f5631a09bf900913de6ab21ea6984973cd2cd1",
131
+ }
132
+
133
+ # Upper-bound l2_gas overhead per SHHH signer kind, in addition to base
134
+ # paymaster execution cost. Numbers from snforge runs at tag v8.4
135
+ # (252-byte calls, single owner, no session key). Paymaster adds ~5M margin.
136
+ # Threshold envelopes: sum the per-owner cost + ~3M aggregation overhead.
137
+ # Session-key envelopes (SNIP-163 4-felt): ~2M + session-policy enforcement.
138
+ SHHH_KIND_GAS_OVERHEAD: dict[ShhhSignerKind, int] = {
139
+ ShhhSignerKind.STARK: 2_000_000,
140
+ ShhhSignerKind.SECP256K1: 5_000_000,
141
+ ShhhSignerKind.EIP191_SECP256K1: 10_000_000,
142
+ ShhhSignerKind.EIP712_SECP256K1: 12_000_000,
143
+ ShhhSignerKind.P256: 30_000_000,
144
+ ShhhSignerKind.ED25519: 33_000_000,
145
+ ShhhSignerKind.WEBAUTHN_P256: 35_000_000,
146
+ ShhhSignerKind.JWT_ES256: 60_000_000,
147
+ ShhhSignerKind.JWT_ES256_APPLE_SUB: 62_000_000,
148
+ ShhhSignerKind.BLS12_381: 80_000_000,
149
+ }
150
+
151
+ # Inner-envelope routing tags per the V8.4 Pluggable-Signer SNIP draft.
152
+ SHHH_ENVELOPE_TAGS = {
153
+ "V2_SNIP12": "V2_SNIP12",
154
+ "V2_THRESHOLD": "V2_THRESHOLD",
155
+ # Session-key envelopes are the SNIP-163 4-felt format (no version tag).
156
+ }
157
+
108
158
 
109
159
  def get_wallet_type_from_class_hash(class_hash: str) -> Optional[str]:
110
160
  """
@@ -114,7 +164,7 @@ def get_wallet_type_from_class_hash(class_hash: str) -> Optional[str]:
114
164
  class_hash: Class hash to look up
115
165
 
116
166
  Returns:
117
- Wallet type string ("CHIPI" or "READY"), or None if unknown
167
+ Wallet type string ("CHIPI", "READY", or "SHHH"), or None if unknown
118
168
  """
119
169
  def normalize(h: str) -> str:
120
170
  import re
@@ -128,12 +178,39 @@ def get_wallet_type_from_class_hash(class_hash: str) -> Optional[str]:
128
178
  return "CHIPI"
129
179
  if any(normalize(h) == normalized for h in LEGACY_CHIPI_CLASS_HASHES):
130
180
  return "CHIPI"
181
+ if normalize(WALLET_CLASS_HASHES[WalletType.SHHH]) == normalized:
182
+ return "SHHH"
183
+ if any(normalize(h) == normalized for h in LEGACY_SHHH_CLASS_HASHES):
184
+ return "SHHH"
131
185
  return None
132
186
 
187
+
188
+ def is_known_shhh_class_hash(class_hash: str) -> bool:
189
+ """
190
+ True if a class hash is a registered SHHH ShhhAccount class (current or
191
+ legacy) OR one of the 10 V8.4 verifier classes. Used by the backend to
192
+ reject unknown class hashes when an integrator opts into SHHH via
193
+ wallet_type="SHHH" (plan D4 safety net — open SDK option, no per-org gate).
194
+ """
195
+ import re
196
+
197
+ def normalize(h: str) -> str:
198
+ return re.sub(r"^0x0+", "0x", h.lower())
199
+
200
+ normalized = normalize(class_hash)
201
+
202
+ if normalize(WALLET_CLASS_HASHES[WalletType.SHHH]) == normalized:
203
+ return True
204
+ if any(normalize(h) == normalized for h in LEGACY_SHHH_CLASS_HASHES):
205
+ return True
206
+ return any(normalize(h) == normalized for h in SHHH_VERIFIER_CLASS_HASHES.values())
207
+
208
+
133
209
  # RPC Endpoints per Wallet Type
134
210
  WALLET_RPC_ENDPOINTS: dict[WalletType, str] = {
135
211
  WalletType.CHIPI: "https://starknet-mainnet.public.blastapi.io/rpc/v0_7",
136
212
  WalletType.READY: "https://cloud.argent-api.com/v1/starknet/mainnet/rpc/v0.7",
213
+ WalletType.SHHH: "https://starknet-mainnet.public.blastapi.io/rpc/v0_7",
137
214
  }
138
215
 
139
216
  # Paymaster Configuration
@@ -58,6 +58,34 @@ async def execute_paymaster_transaction(
58
58
  )
59
59
  raise ValueError(error_msg)
60
60
 
61
+ # SHHH V8.4 ShhhAccount wallets cannot use the legacy
62
+ # prepare-typed-data → sign → execute-sponsored-transaction
63
+ # flow because the Chipi paymaster cannot synthesize SHHH
64
+ # envelopes server-side. Route SHHH OEs through the
65
+ # execute-sponsored-raw forwarder which expects pre-signed
66
+ # calldata. The legacy flow below is unchanged for
67
+ # CHIPI / READY.
68
+ if wallet.wallet_type == WalletType.SHHH:
69
+ from .shhh.execute_paymaster_raw import execute_shhh_sponsored_raw
70
+ from .shhh.snip12_hash import Call as ShhhCall
71
+
72
+ shhh_calls = [
73
+ ShhhCall(
74
+ contract_address=c.get("contractAddress") or c.get("to"),
75
+ entrypoint=c["entrypoint"],
76
+ calldata=list(c.get("calldata") or []),
77
+ )
78
+ for c in calls
79
+ ]
80
+ return await execute_shhh_sponsored_raw(
81
+ client=client,
82
+ bearer_token=bearer_token,
83
+ wallet_public_key=wallet.public_key,
84
+ wallet_encrypted_private_key=wallet.encrypted_private_key,
85
+ encrypt_key=encrypt_key,
86
+ calls=shhh_calls,
87
+ )
88
+
61
89
  # Use READY RPC endpoint for now (matches TypeScript implementation)
62
90
  rpc_url = WALLET_RPC_ENDPOINTS[WalletType.READY]
63
91
  account_class_hash = WALLET_CLASS_HASHES[WalletType.READY]
@@ -168,6 +196,33 @@ def execute_paymaster_transaction_sync(
168
196
  )
169
197
  raise ValueError(error_msg)
170
198
 
199
+ # SHHH parity for the sync API. Sync callers with WalletType.SHHH
200
+ # would otherwise fall into the legacy prepare-typed-data flow,
201
+ # which the paymaster cannot synthesize an envelope for and
202
+ # returns TRANSACTION_EXECUTION_ERROR. Mirror the async branch
203
+ # above via execute_shhh_sponsored_raw_sync (shared payload
204
+ # construction, sync HTTP).
205
+ if wallet.wallet_type == WalletType.SHHH:
206
+ from .shhh.execute_paymaster_raw import execute_shhh_sponsored_raw_sync
207
+ from .shhh.snip12_hash import Call as ShhhCall
208
+
209
+ shhh_calls = [
210
+ ShhhCall(
211
+ contract_address=c.get("contractAddress") or c.get("to"),
212
+ entrypoint=c["entrypoint"],
213
+ calldata=list(c.get("calldata") or []),
214
+ )
215
+ for c in calls
216
+ ]
217
+ return execute_shhh_sponsored_raw_sync(
218
+ client=client,
219
+ bearer_token=bearer_token,
220
+ wallet_public_key=wallet.public_key,
221
+ wallet_encrypted_private_key=wallet.encrypted_private_key,
222
+ encrypt_key=encrypt_key,
223
+ calls=shhh_calls,
224
+ )
225
+
171
226
  # Use READY account class hash (matches TypeScript implementation)
172
227
  account_class_hash = WALLET_CLASS_HASHES[WalletType.READY]
173
228
 
@@ -260,10 +315,15 @@ async def execute_paymaster_transaction_with_session(
260
315
  else:
261
316
  session = session_dict
262
317
 
263
- # Validate this is a CHIPI wallet
264
- if wallet.wallet_type and wallet.wallet_type != WalletType.CHIPI:
318
+ # Accept CHIPI v29 + SHHH V8.4 (both embed SNIP-163 sessions;
319
+ # the 4-felt session sig fast path at account.cairo:389 runs
320
+ # the same on either class).
321
+ if wallet.wallet_type and wallet.wallet_type not in (
322
+ WalletType.CHIPI,
323
+ WalletType.SHHH,
324
+ ):
265
325
  raise ChipiSessionError(
266
- f"Session keys only work with CHIPI wallets. Got: {wallet.wallet_type}",
326
+ f"Session execution requires CHIPI or SHHH wallet type. Got: {wallet.wallet_type}",
267
327
  SESSION_ERRORS["INVALID_WALLET_TYPE_FOR_SESSION"],
268
328
  )
269
329
 
@@ -275,6 +335,34 @@ async def execute_paymaster_transaction_with_session(
275
335
  if not session_private_key:
276
336
  raise ValueError("Failed to decrypt session private key")
277
337
 
338
+ # SHHH branch — route through V8.4 OE path with the 4-felt
339
+ # session sig (bypasses chipi-back's CHIPI-shaped
340
+ # prepare-typed-data + execute-sponsored-transaction). Mirrors
341
+ # the TypeScript SHHH branch shipped in sdks#288.
342
+ if wallet.wallet_type == WalletType.SHHH:
343
+ from .shhh.execute_paymaster_raw import (
344
+ execute_shhh_session_sponsored_raw,
345
+ )
346
+ from .shhh.snip12_hash import Call as ShhhCall
347
+
348
+ shhh_calls = [
349
+ ShhhCall(
350
+ contract_address=c.get("contractAddress") or c.get("to"),
351
+ entrypoint=c["entrypoint"],
352
+ calldata=list(c.get("calldata") or []),
353
+ )
354
+ for c in calls
355
+ ]
356
+ return await execute_shhh_session_sponsored_raw(
357
+ client=client,
358
+ bearer_token=bearer_token,
359
+ wallet_public_key=wallet.public_key,
360
+ session_private_key=session_private_key,
361
+ session_public_key=session.public_key,
362
+ session_valid_until=session.valid_until,
363
+ calls=shhh_calls,
364
+ )
365
+
278
366
  # Use CHIPI RPC endpoint and class hash
279
367
  account_class_hash = WALLET_CLASS_HASHES[WalletType.CHIPI]
280
368
 
@@ -375,13 +463,47 @@ def execute_paymaster_transaction_with_session_sync(
375
463
  else:
376
464
  session = session_dict
377
465
 
378
- # Validate this is a CHIPI wallet
379
- if wallet.wallet_type and wallet.wallet_type != WalletType.CHIPI:
466
+ # Accept CHIPI v29 + SHHH V8.4 — see async path above for details.
467
+ if wallet.wallet_type and wallet.wallet_type not in (
468
+ WalletType.CHIPI,
469
+ WalletType.SHHH,
470
+ ):
380
471
  raise ChipiSessionError(
381
- f"Session keys only work with CHIPI wallets. Got: {wallet.wallet_type}",
472
+ f"Session execution requires CHIPI or SHHH wallet type. Got: {wallet.wallet_type}",
382
473
  SESSION_ERRORS["INVALID_WALLET_TYPE_FOR_SESSION"],
383
474
  )
384
475
 
476
+ # SHHH branch (sync) — same shape as the async path.
477
+ if wallet.wallet_type == WalletType.SHHH:
478
+ session_private_key_sync = decrypt_private_key(
479
+ session.encrypted_private_key, params["encryptKey"]
480
+ )
481
+ if not session_private_key_sync:
482
+ raise ValueError("Failed to decrypt session private key")
483
+
484
+ from .shhh.execute_paymaster_raw import (
485
+ execute_shhh_session_sponsored_raw_sync,
486
+ )
487
+ from .shhh.snip12_hash import Call as ShhhCall
488
+
489
+ shhh_calls = [
490
+ ShhhCall(
491
+ contract_address=c.get("contractAddress") or c.get("to"),
492
+ entrypoint=c["entrypoint"],
493
+ calldata=list(c.get("calldata") or []),
494
+ )
495
+ for c in calls
496
+ ]
497
+ return execute_shhh_session_sponsored_raw_sync(
498
+ client=client,
499
+ bearer_token=bearer_token,
500
+ wallet_public_key=wallet.public_key,
501
+ session_private_key=session_private_key_sync,
502
+ session_public_key=session.public_key,
503
+ session_valid_until=session.valid_until,
504
+ calls=shhh_calls,
505
+ )
506
+
385
507
  # Use CHIPI account class hash
386
508
  account_class_hash = WALLET_CLASS_HASHES[WalletType.CHIPI]
387
509
 
@@ -23,6 +23,7 @@ from .wallet import (
23
23
  GetWalletResponse,
24
24
  PasskeyMetadata,
25
25
  PrepareWalletCreationResponse,
26
+ ShhhSignerKind,
26
27
  WalletData,
27
28
  WalletType,
28
29
  )
@@ -101,6 +102,7 @@ __all__ = [
101
102
  "GetWalletResponse",
102
103
  "PasskeyMetadata",
103
104
  "PrepareWalletCreationResponse",
105
+ "ShhhSignerKind",
104
106
  "WalletData",
105
107
  "WalletType",
106
108
  # Transaction
@@ -22,6 +22,12 @@ class ChainToken(str, Enum):
22
22
  OTHER = "OTHER"
23
23
 
24
24
 
25
+ class Currency(str, Enum):
26
+ """Local currencies supported by Chipi services (e.g. SKU purchases)."""
27
+ MXN = "MXN"
28
+ USD = "USD"
29
+
30
+
25
31
  class ChipiSDKConfig(BaseModel):
26
32
  """Configuration for initializing the Chipi SDK."""
27
33
 
@@ -0,0 +1,40 @@
1
+ """Bill payment / SKU purchase types — mirrors @chipi-stack/types CreateSkuPurchaseParams."""
2
+
3
+ from pydantic import BaseModel, ConfigDict, Field
4
+
5
+ from .core import Chain, ChainToken, Currency
6
+ from .wallet import WalletData, to_camel
7
+
8
+
9
+ class CreateSkuPurchaseParams(BaseModel):
10
+ """
11
+ Parameters for charging a user's gasless wallet for a SKU (bill payment,
12
+ gift card, etc.). Mirrors @chipi-stack/types CreateSkuPurchaseParams; the
13
+ backend endpoint is POST /sku-purchases.
14
+ """
15
+
16
+ model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
17
+
18
+ sku_id: str = Field(..., description="SKU identifier from getSkuList / getSku")
19
+ sku_reference: str = Field(
20
+ ...,
21
+ description=(
22
+ "User-facing reference required by the SKU (e.g. phone number for a "
23
+ "phone recharge, account number for a utility bill). Validated "
24
+ "server-side against the SKU's referenceRegexValidation."
25
+ ),
26
+ )
27
+ currency_amount: float = Field(
28
+ ...,
29
+ gt=0,
30
+ description="Amount in the SKU's local currency (e.g. 200 for $200 MXN). Must be > 0.",
31
+ )
32
+ currency: Currency = Field(..., description="Local currency of currency_amount.")
33
+ chain: Chain = Field(..., description="Settlement chain (currently STARKNET).")
34
+ token: ChainToken = Field(
35
+ ..., description="Token used to pay (typically USDC)."
36
+ )
37
+ encrypt_key: str = Field(..., description="User PIN that decrypts the wallet.")
38
+ wallet: WalletData = Field(
39
+ ..., description="The user's gasless wallet (publicKey + encryptedPrivateKey)."
40
+ )