chipi-stack 2.0.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.
- chipi_sdk/__init__.py +342 -0
- chipi_sdk/client.py +505 -0
- chipi_sdk/constants.py +171 -0
- chipi_sdk/encryption.py +179 -0
- chipi_sdk/errors.py +130 -0
- chipi_sdk/execute_paymaster.py +434 -0
- chipi_sdk/formatters.py +154 -0
- chipi_sdk/models/__init__.py +145 -0
- chipi_sdk/models/core.py +96 -0
- chipi_sdk/models/session.py +119 -0
- chipi_sdk/models/sku.py +28 -0
- chipi_sdk/models/sku_transaction.py +30 -0
- chipi_sdk/models/transaction.py +192 -0
- chipi_sdk/models/user.py +31 -0
- chipi_sdk/models/wallet.py +178 -0
- chipi_sdk/models/x402.py +117 -0
- chipi_sdk/py.typed +1 -0
- chipi_sdk/sdk.py +1021 -0
- chipi_sdk/sessions.py +836 -0
- chipi_sdk/sku_transactions.py +58 -0
- chipi_sdk/skus.py +93 -0
- chipi_sdk/transactions.py +447 -0
- chipi_sdk/users.py +92 -0
- chipi_sdk/validators.py +75 -0
- chipi_sdk/wallets.py +465 -0
- chipi_sdk/x402_client.py +207 -0
- chipi_sdk/x402_facilitator.py +200 -0
- chipi_sdk/x402_middleware.py +280 -0
- chipi_stack-2.0.0.dist-info/METADATA +366 -0
- chipi_stack-2.0.0.dist-info/RECORD +33 -0
- chipi_stack-2.0.0.dist-info/WHEEL +5 -0
- chipi_stack-2.0.0.dist-info/licenses/LICENSE +21 -0
- chipi_stack-2.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"""Wallet-related types and models."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from enum import Enum
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from pydantic import BaseModel, Field, ConfigDict
|
|
7
|
+
|
|
8
|
+
from .core import Chain, ChainToken
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def to_camel(string: str) -> str:
|
|
12
|
+
"""Convert snake_case to camelCase."""
|
|
13
|
+
components = string.split('_')
|
|
14
|
+
return components[0] + ''.join(x.title() for x in components[1:])
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class WalletType(str, Enum):
|
|
18
|
+
"""
|
|
19
|
+
Supported wallet types.
|
|
20
|
+
|
|
21
|
+
- CHIPI: OpenZeppelin account with SNIP-9 session keys support (default)
|
|
22
|
+
- READY: Argent X Account v0.4.0
|
|
23
|
+
"""
|
|
24
|
+
CHIPI = "CHIPI"
|
|
25
|
+
READY = "READY"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class WalletData(BaseModel):
|
|
29
|
+
"""Core wallet data structure."""
|
|
30
|
+
|
|
31
|
+
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
32
|
+
|
|
33
|
+
public_key: str = Field(..., description="Wallet public address")
|
|
34
|
+
encrypted_private_key: str = Field(..., description="AES encrypted private key")
|
|
35
|
+
wallet_type: Optional[WalletType] = Field(None, description="Type of wallet")
|
|
36
|
+
normalized_public_key: Optional[str] = Field(None, description="Normalized public key")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class DeploymentData(BaseModel):
|
|
40
|
+
"""Contract deployment data."""
|
|
41
|
+
|
|
42
|
+
class_hash: str
|
|
43
|
+
salt: str
|
|
44
|
+
unique: str
|
|
45
|
+
calldata: list[str]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class CreateWalletParams(BaseModel):
|
|
49
|
+
"""Parameters for creating a new wallet."""
|
|
50
|
+
|
|
51
|
+
encrypt_key: Optional[str] = Field(None, description="Encryption key for private key")
|
|
52
|
+
external_user_id: str = Field(..., description="External user identifier")
|
|
53
|
+
user_id: Optional[str] = Field(None, description="Internal user ID")
|
|
54
|
+
wallet_type: Optional[WalletType] = Field(WalletType.CHIPI, description="Type of wallet to create")
|
|
55
|
+
use_passkey: Optional[bool] = Field(False, description="Whether to use passkey authentication")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class GetWalletResponse(BaseModel):
|
|
59
|
+
"""
|
|
60
|
+
Response from wallet retrieval and creation.
|
|
61
|
+
|
|
62
|
+
Flat object matching the backend API response. Same shape for both
|
|
63
|
+
createWallet and getWallet — no nesting, no txHash.
|
|
64
|
+
Aligned with TypeScript GetWalletResponse (types/src/wallet.ts).
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
68
|
+
|
|
69
|
+
id: str
|
|
70
|
+
external_user_id: str = Field(..., description="External user identifier")
|
|
71
|
+
organization_id: Optional[str] = None
|
|
72
|
+
api_public_key: str = Field(..., description="Organization API public key")
|
|
73
|
+
public_key: str = Field(..., description="Wallet public address")
|
|
74
|
+
normalized_public_key: str = Field(..., description="Normalized public key")
|
|
75
|
+
encrypted_private_key: str = Field(..., description="AES encrypted private key")
|
|
76
|
+
is_deployed: bool = Field(..., description="Whether wallet contract is deployed")
|
|
77
|
+
created_at: Optional[datetime] = None
|
|
78
|
+
updated_at: Optional[datetime] = None
|
|
79
|
+
wallet_type: WalletType = Field(WalletType.CHIPI, description="Type of wallet")
|
|
80
|
+
chain: Chain = Field(Chain.STARKNET, description="Blockchain network")
|
|
81
|
+
class_hash: Optional[str] = Field(None, description="Contract class hash used for deployment")
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
CreateWalletResponse = GetWalletResponse
|
|
85
|
+
"""CreateWalletResponse is the same shape as GetWalletResponse (alias)."""
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class GetWalletParams(BaseModel):
|
|
89
|
+
"""Parameters for retrieving a wallet."""
|
|
90
|
+
|
|
91
|
+
external_user_id: str = Field(..., description="External user identifier")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class GetTokenBalanceParams(BaseModel):
|
|
95
|
+
"""Parameters for querying token balance."""
|
|
96
|
+
|
|
97
|
+
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
98
|
+
|
|
99
|
+
external_user_id: Optional[str] = Field(None, description="External user identifier")
|
|
100
|
+
wallet_public_key: Optional[str] = Field(None, description="Wallet public key")
|
|
101
|
+
chain_token: ChainToken = Field(..., description="Token to query")
|
|
102
|
+
chain: Chain = Field(..., description="Blockchain network")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class GetTokenBalanceResponse(BaseModel):
|
|
106
|
+
"""Response from token balance query."""
|
|
107
|
+
|
|
108
|
+
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
109
|
+
|
|
110
|
+
chain: Chain
|
|
111
|
+
chain_token: ChainToken
|
|
112
|
+
chain_token_address: str
|
|
113
|
+
decimals: int
|
|
114
|
+
balance: str
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class PrepareWalletCreationResponse(BaseModel):
|
|
118
|
+
"""Response from wallet creation preparation."""
|
|
119
|
+
|
|
120
|
+
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
121
|
+
|
|
122
|
+
typed_data: dict
|
|
123
|
+
account_class_hash: str
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class CreateCustodialWalletParams(BaseModel):
|
|
127
|
+
"""Parameters for creating a custodial wallet."""
|
|
128
|
+
|
|
129
|
+
chain: Chain
|
|
130
|
+
org_id: str
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class PasskeyMetadata(BaseModel):
|
|
134
|
+
"""Passkey authentication metadata."""
|
|
135
|
+
|
|
136
|
+
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
137
|
+
|
|
138
|
+
credential_id: str
|
|
139
|
+
created_at: str
|
|
140
|
+
user_id: str
|
|
141
|
+
prf_supported: bool
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class PrepareWalletUpgradeParams(BaseModel):
|
|
145
|
+
"""Parameters for preparing a wallet upgrade."""
|
|
146
|
+
|
|
147
|
+
wallet_address: str = Field(..., description="Wallet address to upgrade")
|
|
148
|
+
target_class_hash: Optional[str] = Field(None, description="Target class hash (defaults to latest CHIPI)")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class PrepareWalletUpgradeResponse(BaseModel):
|
|
152
|
+
"""Response from prepare-upgrade containing typed data for signing."""
|
|
153
|
+
|
|
154
|
+
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
155
|
+
|
|
156
|
+
typed_data: dict
|
|
157
|
+
current_class_hash: str
|
|
158
|
+
target_class_hash: str
|
|
159
|
+
current_wallet_type: str
|
|
160
|
+
target_wallet_type: str
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class ExecuteWalletUpgradeParams(BaseModel):
|
|
164
|
+
"""Parameters for executing a wallet upgrade after signing."""
|
|
165
|
+
|
|
166
|
+
wallet_address: str = Field(..., description="Wallet address being upgraded")
|
|
167
|
+
typed_data: dict = Field(..., description="SNIP-12 typed data from prepare step")
|
|
168
|
+
signature: list[str] = Field(..., description="User signature over the typed data")
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
class ExecuteWalletUpgradeResponse(BaseModel):
|
|
172
|
+
"""Response from wallet upgrade execution."""
|
|
173
|
+
|
|
174
|
+
model_config = ConfigDict(populate_by_name=True, alias_generator=to_camel)
|
|
175
|
+
|
|
176
|
+
transaction_hash: str
|
|
177
|
+
new_class_hash: str
|
|
178
|
+
new_wallet_type: str
|
chipi_sdk/models/x402.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""x402 Payment Protocol types for HTTP 402 pay-per-request APIs."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from pydantic import BaseModel, Field, field_validator
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class PaymentRequirement(BaseModel):
|
|
8
|
+
"""Payment requirement from 402 response PAYMENT-REQUIRED header."""
|
|
9
|
+
|
|
10
|
+
scheme: str = Field("exact", description="Payment scheme")
|
|
11
|
+
network: str = Field("starknet-mainnet", description="Network identifier")
|
|
12
|
+
max_amount_required: str = Field(..., alias="maxAmountRequired", description="Amount in token base units")
|
|
13
|
+
resource: str = Field(..., description="URL of the resource being paid for")
|
|
14
|
+
description: Optional[str] = Field(None, description="Human-readable description")
|
|
15
|
+
mime_type: Optional[str] = Field(None, alias="mimeType", description="MIME type of the resource")
|
|
16
|
+
pay_to: str = Field(..., alias="payTo", description="Recipient address (merchant)")
|
|
17
|
+
max_timeout_seconds: int = Field(..., alias="maxTimeoutSeconds", description="Max seconds before payment expires")
|
|
18
|
+
asset: str = Field(..., description="Token contract address (USDC)")
|
|
19
|
+
extra: Optional[dict] = Field(None, description="Additional protocol-specific data")
|
|
20
|
+
|
|
21
|
+
model_config = {"populate_by_name": True}
|
|
22
|
+
|
|
23
|
+
@field_validator("max_amount_required")
|
|
24
|
+
@classmethod
|
|
25
|
+
def validate_amount(cls, v: str) -> str:
|
|
26
|
+
try:
|
|
27
|
+
val = int(v)
|
|
28
|
+
except (ValueError, TypeError):
|
|
29
|
+
raise ValueError(f"maxAmountRequired must be a valid integer string, got: {v!r}")
|
|
30
|
+
if val <= 0:
|
|
31
|
+
raise ValueError(f"maxAmountRequired must be positive, got: {val}")
|
|
32
|
+
return v
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PaymentSignature(BaseModel):
|
|
36
|
+
"""SNIP-12 signature."""
|
|
37
|
+
|
|
38
|
+
r: str
|
|
39
|
+
s: str
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class PaymentPayloadData(BaseModel):
|
|
43
|
+
"""Inner payload of a signed payment."""
|
|
44
|
+
|
|
45
|
+
signature: PaymentSignature
|
|
46
|
+
from_address: str = Field(..., alias="fromAddress")
|
|
47
|
+
to_address: str = Field(..., alias="toAddress")
|
|
48
|
+
amount: str
|
|
49
|
+
asset: str
|
|
50
|
+
valid_until: int = Field(..., alias="validUntil")
|
|
51
|
+
nonce: str
|
|
52
|
+
|
|
53
|
+
model_config = {"populate_by_name": True}
|
|
54
|
+
|
|
55
|
+
@field_validator("amount")
|
|
56
|
+
@classmethod
|
|
57
|
+
def validate_amount(cls, v: str) -> str:
|
|
58
|
+
try:
|
|
59
|
+
val = int(v)
|
|
60
|
+
except (ValueError, TypeError):
|
|
61
|
+
raise ValueError(f"amount must be a valid integer string, got: {v!r}")
|
|
62
|
+
if val <= 0:
|
|
63
|
+
raise ValueError(f"amount must be positive, got: {val}")
|
|
64
|
+
return v
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class PaymentPayload(BaseModel):
|
|
68
|
+
"""Signed payment payload sent in X-PAYMENT header."""
|
|
69
|
+
|
|
70
|
+
x402_version: int = Field(1, alias="x402Version")
|
|
71
|
+
scheme: str = Field("exact")
|
|
72
|
+
network: str = Field("starknet-mainnet")
|
|
73
|
+
payload: PaymentPayloadData
|
|
74
|
+
|
|
75
|
+
model_config = {"populate_by_name": True}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class VerifyResponse(BaseModel):
|
|
79
|
+
"""Facilitator verify response."""
|
|
80
|
+
|
|
81
|
+
is_valid: bool = Field(..., alias="isValid")
|
|
82
|
+
invalid_reason: Optional[str] = Field(None, alias="invalidReason")
|
|
83
|
+
|
|
84
|
+
model_config = {"populate_by_name": True}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class SettleResponse(BaseModel):
|
|
88
|
+
"""Facilitator settle response."""
|
|
89
|
+
|
|
90
|
+
success: bool
|
|
91
|
+
transaction_hash: Optional[str] = Field(None, alias="transactionHash")
|
|
92
|
+
error_reason: Optional[str] = Field(None, alias="errorReason")
|
|
93
|
+
network_id: Optional[str] = Field(None, alias="networkId")
|
|
94
|
+
|
|
95
|
+
model_config = {"populate_by_name": True}
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class X402ClientConfig(BaseModel):
|
|
99
|
+
"""x402 client configuration."""
|
|
100
|
+
|
|
101
|
+
max_payment_amount: Optional[str] = Field(None, description="Max amount per payment (human-readable USDC)")
|
|
102
|
+
allowed_recipients: Optional[list[str]] = Field(None, description="Allowed recipient addresses")
|
|
103
|
+
header_name: str = Field("X-PAYMENT", description="Custom header name")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class X402FacilitatorConfig(BaseModel):
|
|
107
|
+
"""x402 facilitator configuration."""
|
|
108
|
+
# NonceStore is not a Pydantic model — it's passed as a protocol/ABC at runtime
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class X402PaymentConfig(BaseModel):
|
|
113
|
+
"""Payment configuration for a protected endpoint."""
|
|
114
|
+
|
|
115
|
+
amount: str = Field(..., description="Amount in human-readable units (e.g. '0.01')")
|
|
116
|
+
pay_to: str = Field(..., description="Merchant receiving address")
|
|
117
|
+
description: Optional[str] = Field(None, description="Human-readable description")
|
chipi_sdk/py.typed
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Marker file for PEP 561 - indicates this package supports type hints
|