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