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.
- {chipi_stack-2.0.0/chipi_stack.egg-info → chipi_stack-2.2.0}/PKG-INFO +32 -5
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/README.md +27 -3
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/__init__.py +24 -1
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/constants.py +80 -3
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/execute_paymaster.py +128 -6
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/__init__.py +2 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/core.py +6 -0
- chipi_stack-2.2.0/chipi_sdk/models/sku_purchase.py +40 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/wallet.py +58 -5
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/sdk.py +59 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/sessions.py +57 -24
- chipi_stack-2.2.0/chipi_sdk/shhh/__init__.py +249 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/compute_wallet_address.py +97 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/execute_paymaster_raw.py +439 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/migrate.py +358 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/oe.py +189 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/recovery.py +450 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/signers/__init__.py +77 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/signers/ed25519.py +157 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/signers/eip191.py +261 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/signers/jwt_apple_sub.py +517 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/signers/stark.py +92 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/snip12_hash.py +214 -0
- chipi_stack-2.2.0/chipi_sdk/shhh/threshold.py +295 -0
- chipi_stack-2.2.0/chipi_sdk/sku_purchases.py +98 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/wallets.py +223 -49
- {chipi_stack-2.0.0 → chipi_stack-2.2.0/chipi_stack.egg-info}/PKG-INFO +32 -5
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_stack.egg-info/SOURCES.txt +15 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_stack.egg-info/requires.txt +4 -1
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/pyproject.toml +10 -2
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/LICENSE +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/MANIFEST.in +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/client.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/encryption.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/errors.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/formatters.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/session.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/sku.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/sku_transaction.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/transaction.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/user.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/models/x402.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/py.typed +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/sku_transactions.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/skus.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/transactions.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/users.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/validators.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/x402_client.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/x402_facilitator.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_sdk/x402_middleware.py +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_stack.egg-info/dependency_links.txt +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/chipi_stack.egg-info/top_level.txt +0 -0
- {chipi_stack-2.0.0 → chipi_stack-2.2.0}/setup.cfg +0 -0
- {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.
|
|
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
|
-
[](https://badge.fury.io/py/chipi-stack)
|
|
43
46
|
[](https://www.python.org/downloads/)
|
|
44
47
|
[](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-
|
|
65
|
+
pip install chipi-stack
|
|
61
66
|
```
|
|
62
67
|
|
|
63
68
|
Or with uv:
|
|
64
69
|
|
|
65
70
|
```bash
|
|
66
|
-
uv add chipi-
|
|
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
|
-
[](https://badge.fury.io/py/chipi-stack)
|
|
4
4
|
[](https://www.python.org/downloads/)
|
|
5
5
|
[](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-
|
|
23
|
+
pip install chipi-stack
|
|
22
24
|
```
|
|
23
25
|
|
|
24
26
|
Or with uv:
|
|
25
27
|
|
|
26
28
|
```bash
|
|
27
|
-
uv add chipi-
|
|
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.
|
|
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
|
-
"
|
|
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 "
|
|
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
|
-
#
|
|
264
|
-
|
|
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
|
|
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
|
-
#
|
|
379
|
-
if wallet.wallet_type and wallet.wallet_type
|
|
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
|
|
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
|
+
)
|