@chipi-stack/core 0.4.1 → 0.6.0
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.
- package/README.md +14 -0
- package/dist/index.cjs +11093 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1544 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +32 -4
- package/dist/index.js.map +1 -1
- package/package.json +14 -6
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1544 @@
|
|
|
1
|
+
import { Account, Call, InvokeFunctionResponse, EstimateFeeResponseOverhead, Signer, Signature, ProviderOptions, ProviderInterface, CairoVersion, TypedData, CairoCustomEnum, RpcProvider } from 'starknet';
|
|
2
|
+
import { PaymasterAdapter, X402ClientConfig, PaymentRequirement, PaymentPayload } from '@chipi-stack/types';
|
|
3
|
+
import { ProvingServiceProofProvider } from 'starknet-sdk';
|
|
4
|
+
|
|
5
|
+
/** Minimal token info needed by Amount. */
|
|
6
|
+
interface TokenInfo {
|
|
7
|
+
symbol: string;
|
|
8
|
+
decimals: number;
|
|
9
|
+
address: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Immutable representation of a token amount.
|
|
13
|
+
* Stores raw base units (e.g., wei for ETH, micro-units for USDC).
|
|
14
|
+
* All arithmetic is exact BigInt math — no floating point.
|
|
15
|
+
*/
|
|
16
|
+
declare class Amount {
|
|
17
|
+
/** Raw value in base units (smallest denomination). */
|
|
18
|
+
readonly raw: bigint;
|
|
19
|
+
/** Number of decimal places for this token. */
|
|
20
|
+
readonly decimals: number;
|
|
21
|
+
/** Token symbol (e.g., "USDC", "ETH"). */
|
|
22
|
+
readonly symbol: string;
|
|
23
|
+
private constructor();
|
|
24
|
+
private static assertValidDecimals;
|
|
25
|
+
/**
|
|
26
|
+
* Parse a human-readable string into an Amount.
|
|
27
|
+
* @param value - Human-readable value (e.g., "1.5")
|
|
28
|
+
* @param token - Token info with decimals and symbol
|
|
29
|
+
* @throws If value is negative, non-numeric, or has too many decimal places
|
|
30
|
+
*/
|
|
31
|
+
static parse(value: string, token: TokenInfo): Amount;
|
|
32
|
+
/**
|
|
33
|
+
* Create an Amount from a raw bigint value (base units).
|
|
34
|
+
* @param raw - Raw value in base units
|
|
35
|
+
* @param decimals - Token decimal places
|
|
36
|
+
* @param symbol - Token symbol (defaults to "")
|
|
37
|
+
*/
|
|
38
|
+
static fromRaw(raw: bigint, decimals: number, symbol?: string): Amount;
|
|
39
|
+
/** Add two amounts. Both must have the same decimals. */
|
|
40
|
+
add(other: Amount): Amount;
|
|
41
|
+
/**
|
|
42
|
+
* Subtract an amount.
|
|
43
|
+
* @throws If result would be negative
|
|
44
|
+
*/
|
|
45
|
+
subtract(other: Amount): Amount;
|
|
46
|
+
/**
|
|
47
|
+
* Multiply by a scalar bigint.
|
|
48
|
+
* @throws If scalar is negative
|
|
49
|
+
*/
|
|
50
|
+
multiply(scalar: bigint): Amount;
|
|
51
|
+
/**
|
|
52
|
+
* Divide by a scalar bigint. Truncates (no rounding).
|
|
53
|
+
* @throws If divisor is zero or negative
|
|
54
|
+
*/
|
|
55
|
+
divide(divisor: bigint): Amount;
|
|
56
|
+
eq(other: Amount): boolean;
|
|
57
|
+
gt(other: Amount): boolean;
|
|
58
|
+
gte(other: Amount): boolean;
|
|
59
|
+
lt(other: Amount): boolean;
|
|
60
|
+
lte(other: Amount): boolean;
|
|
61
|
+
isZero(): boolean;
|
|
62
|
+
/** Returns the raw bigint value (base units). */
|
|
63
|
+
toBase(): bigint;
|
|
64
|
+
/**
|
|
65
|
+
* Returns human-readable string (e.g., "1.5").
|
|
66
|
+
* Trailing zeros after decimal are preserved to one place minimum.
|
|
67
|
+
*/
|
|
68
|
+
toUnit(): string;
|
|
69
|
+
/**
|
|
70
|
+
* Returns formatted string with symbol (e.g., "1.5 USDC").
|
|
71
|
+
* @param compressed - If true, shorten large numbers (e.g., "1.5M USDC")
|
|
72
|
+
*/
|
|
73
|
+
toFormatted(compressed?: boolean): string;
|
|
74
|
+
private assertSameDecimals;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Typed ERC20 contract wrapper.
|
|
79
|
+
* Generates Call objects for approve/transfer and queries for balance/allowance.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* const usdc = new Erc20({ symbol: 'USDC', decimals: 6, address: '0x...' }, account);
|
|
83
|
+
* const balance = await usdc.balanceOf(myAddress);
|
|
84
|
+
* console.log(balance.toFormatted()); // "150.5 USDC"
|
|
85
|
+
*/
|
|
86
|
+
declare class Erc20 {
|
|
87
|
+
private readonly token;
|
|
88
|
+
private readonly account;
|
|
89
|
+
constructor(token: TokenInfo, account: Account);
|
|
90
|
+
/**
|
|
91
|
+
* Query the balance of an address.
|
|
92
|
+
* @returns Amount representing the balance
|
|
93
|
+
*/
|
|
94
|
+
balanceOf(address: string): Promise<Amount>;
|
|
95
|
+
/**
|
|
96
|
+
* Query the allowance of owner for spender.
|
|
97
|
+
* @returns Amount representing the allowance
|
|
98
|
+
*/
|
|
99
|
+
allowance(owner: string, spender: string): Promise<Amount>;
|
|
100
|
+
/**
|
|
101
|
+
* Build an approve Call (does not execute).
|
|
102
|
+
* @returns Call object for use with TxBuilder or Account.execute()
|
|
103
|
+
*/
|
|
104
|
+
approveCall(spender: string, amount: Amount): Call;
|
|
105
|
+
/**
|
|
106
|
+
* Build a transfer Call (does not execute).
|
|
107
|
+
* @returns Call object for use with TxBuilder or Account.execute()
|
|
108
|
+
*/
|
|
109
|
+
transferCall(recipient: string, amount: Amount): Call;
|
|
110
|
+
private assertCompatibleAmount;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
type Network = "mainnet" | "sepolia";
|
|
114
|
+
interface TokenEntry extends TokenInfo {
|
|
115
|
+
name: string;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Registry for looking up token metadata by symbol or address.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* const registry = new TokenRegistry('mainnet');
|
|
122
|
+
* const usdc = registry.bySymbol('USDC');
|
|
123
|
+
* const amount = Amount.parse('10.0', usdc!);
|
|
124
|
+
*/
|
|
125
|
+
declare class TokenRegistry {
|
|
126
|
+
private readonly tokens;
|
|
127
|
+
private readonly bySymbolMap;
|
|
128
|
+
private readonly byAddressMap;
|
|
129
|
+
constructor(network: Network);
|
|
130
|
+
/** Find a token by its symbol (case-insensitive). */
|
|
131
|
+
bySymbol(symbol: string): TokenEntry | undefined;
|
|
132
|
+
/** Find a token by its contract address (case-insensitive). */
|
|
133
|
+
byAddress(address: string): TokenEntry | undefined;
|
|
134
|
+
/** List all tokens in this registry. */
|
|
135
|
+
all(): TokenEntry[];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
interface TransferTarget {
|
|
139
|
+
to: string;
|
|
140
|
+
amount: bigint;
|
|
141
|
+
}
|
|
142
|
+
interface PreflightResult$1 {
|
|
143
|
+
transaction_trace: unknown;
|
|
144
|
+
fee_estimation: {
|
|
145
|
+
overall_fee: bigint;
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Fluent builder for batching Starknet calls.
|
|
151
|
+
* All calls execute atomically via Account.execute().
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* const result = await new TxBuilder(account)
|
|
155
|
+
* .approve(tokenAddr, spenderAddr, amount)
|
|
156
|
+
* .transfer(tokenAddr, [{ to: recipient, amount: 1000n }])
|
|
157
|
+
* .send();
|
|
158
|
+
*/
|
|
159
|
+
interface TxBuilderOptions {
|
|
160
|
+
/** PaymasterAdapter for gasless transactions via sendSponsored(). */
|
|
161
|
+
paymaster?: PaymasterAdapter;
|
|
162
|
+
}
|
|
163
|
+
declare class TxBuilder {
|
|
164
|
+
private readonly account;
|
|
165
|
+
private readonly paymaster?;
|
|
166
|
+
private readonly _calls;
|
|
167
|
+
private sent;
|
|
168
|
+
constructor(account: Account, opts?: TxBuilderOptions);
|
|
169
|
+
/** Returns a copy of the current call batch. */
|
|
170
|
+
calls(): Call[];
|
|
171
|
+
/**
|
|
172
|
+
* Add one or more raw calls.
|
|
173
|
+
* @param call - A single Call or array of Calls
|
|
174
|
+
*/
|
|
175
|
+
add(call: Call | Call[]): this;
|
|
176
|
+
/**
|
|
177
|
+
* Add an ERC20 approve call.
|
|
178
|
+
* @param token - Token contract address
|
|
179
|
+
* @param spender - Address to approve
|
|
180
|
+
* @param amount - Raw amount in base units
|
|
181
|
+
*/
|
|
182
|
+
approve(token: string, spender: string, amount: bigint): this;
|
|
183
|
+
/**
|
|
184
|
+
* Add one or more ERC20 transfer calls.
|
|
185
|
+
* @param token - Token contract address
|
|
186
|
+
* @param targets - Array of { to, amount } pairs
|
|
187
|
+
*/
|
|
188
|
+
transfer(token: string, targets: TransferTarget[]): this;
|
|
189
|
+
/**
|
|
190
|
+
* Execute all batched calls atomically.
|
|
191
|
+
* @throws If no calls have been added
|
|
192
|
+
* @throws If send() was already called
|
|
193
|
+
*/
|
|
194
|
+
send(): Promise<InvokeFunctionResponse>;
|
|
195
|
+
/**
|
|
196
|
+
* Execute via a paymaster (gasless). Requires a PaymasterAdapter.
|
|
197
|
+
*
|
|
198
|
+
* The paymaster handles: prepare typed data -> sign -> submit.
|
|
199
|
+
* For external wallets (Argent X, Braavos), signing triggers the wallet popup.
|
|
200
|
+
*
|
|
201
|
+
* @returns Transaction hash
|
|
202
|
+
* @throws If no paymaster was configured
|
|
203
|
+
* @throws If no calls have been added
|
|
204
|
+
* @throws If sendSponsored() or send() was already called
|
|
205
|
+
*/
|
|
206
|
+
sendSponsored(): Promise<string>;
|
|
207
|
+
/**
|
|
208
|
+
* Estimate fees for the current batch without executing.
|
|
209
|
+
* @throws If no calls have been added
|
|
210
|
+
*/
|
|
211
|
+
estimateFee(): Promise<EstimateFeeResponseOverhead>;
|
|
212
|
+
/**
|
|
213
|
+
* Simulate the transaction without submitting to the network.
|
|
214
|
+
* Useful for checking if a transaction would succeed.
|
|
215
|
+
* @throws If no calls have been added
|
|
216
|
+
*/
|
|
217
|
+
preflight(): Promise<PreflightResult$1>;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Result of a signing operation. */
|
|
221
|
+
interface SignResult {
|
|
222
|
+
r: string;
|
|
223
|
+
s: string;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Unified signer interface.
|
|
227
|
+
* Implementations wrap different key management strategies
|
|
228
|
+
* (local key, passkey, external provider).
|
|
229
|
+
*/
|
|
230
|
+
interface SignerAdapter {
|
|
231
|
+
/** Get the public key associated with this signer. */
|
|
232
|
+
getPublicKey(): Promise<string>;
|
|
233
|
+
/** Sign a message hash. */
|
|
234
|
+
sign(messageHash: string): Promise<SignResult>;
|
|
235
|
+
/** Get the account address derived from this signer. */
|
|
236
|
+
getAccountAddress(): Promise<string>;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Signer backed by a local private key.
|
|
241
|
+
* Equivalent to StarkZap's StarkSigner.
|
|
242
|
+
*
|
|
243
|
+
* WARNING: Only for development/testing.
|
|
244
|
+
* Never hardcode private keys in production.
|
|
245
|
+
*/
|
|
246
|
+
declare class DirectSigner implements SignerAdapter {
|
|
247
|
+
private readonly privateKey;
|
|
248
|
+
private readonly publicKey;
|
|
249
|
+
private readonly accountAddress;
|
|
250
|
+
constructor(privateKey: string, accountAddress?: string);
|
|
251
|
+
getPublicKey(): Promise<string>;
|
|
252
|
+
sign(messageHash: string): Promise<SignResult>;
|
|
253
|
+
getAccountAddress(): Promise<string>;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Signer that wraps @chipi-stack/passkey functions.
|
|
258
|
+
* Does NOT modify @chipi-stack/passkey — only wraps it.
|
|
259
|
+
*
|
|
260
|
+
* @param authenticateFn - The authenticatePasskey function from @chipi-stack/passkey
|
|
261
|
+
* @param publicKey - The passkey public key (obtained during registration)
|
|
262
|
+
*/
|
|
263
|
+
declare class PasskeySigner implements SignerAdapter {
|
|
264
|
+
private readonly authenticateFn;
|
|
265
|
+
private readonly pubKey;
|
|
266
|
+
private readonly accountAddress;
|
|
267
|
+
constructor(opts: {
|
|
268
|
+
authenticateFn: (challenge: string) => Promise<{
|
|
269
|
+
r: string;
|
|
270
|
+
s: string;
|
|
271
|
+
}>;
|
|
272
|
+
publicKey: string;
|
|
273
|
+
accountAddress: string;
|
|
274
|
+
});
|
|
275
|
+
getPublicKey(): Promise<string>;
|
|
276
|
+
sign(messageHash: string): Promise<SignResult>;
|
|
277
|
+
getAccountAddress(): Promise<string>;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Adapter for external signer providers (Privy, Cartridge, etc.).
|
|
282
|
+
* Consumers provide the signing function — ExternalSigner just wraps the interface.
|
|
283
|
+
*/
|
|
284
|
+
declare class ExternalSigner implements SignerAdapter {
|
|
285
|
+
private readonly opts;
|
|
286
|
+
constructor(opts: {
|
|
287
|
+
getPublicKey: () => Promise<string>;
|
|
288
|
+
sign: (messageHash: string) => Promise<SignResult>;
|
|
289
|
+
getAccountAddress: () => Promise<string>;
|
|
290
|
+
});
|
|
291
|
+
getPublicKey(): Promise<string>;
|
|
292
|
+
sign(messageHash: string): Promise<SignResult>;
|
|
293
|
+
getAccountAddress(): Promise<string>;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Bridge between SignerAdapter and starknet.js Signer.
|
|
298
|
+
*
|
|
299
|
+
* Extends starknet.js `Signer`, overriding `signRaw()` to delegate to
|
|
300
|
+
* `SignerAdapter.sign()`. All hash computation is handled by starknet.js.
|
|
301
|
+
*
|
|
302
|
+
* This allows any SignerAdapter (DirectSigner, PasskeySigner, ExternalSigner)
|
|
303
|
+
* to be used where starknet.js expects a Signer instance (e.g., Account constructor).
|
|
304
|
+
*/
|
|
305
|
+
declare class StarknetSignerAdapter extends Signer {
|
|
306
|
+
private readonly adapter;
|
|
307
|
+
constructor(adapter: SignerAdapter);
|
|
308
|
+
getPubKey(): Promise<string>;
|
|
309
|
+
protected signRaw(msgHash: string): Promise<Signature>;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
interface CreateAccountOptions {
|
|
313
|
+
/** Any SignerAdapter implementation (DirectSigner, PasskeySigner, ExternalSigner). */
|
|
314
|
+
signer: SignerAdapter;
|
|
315
|
+
/** Starknet provider or provider options. */
|
|
316
|
+
provider: ProviderOptions | ProviderInterface;
|
|
317
|
+
/** Override the account address (defaults to signer.getAccountAddress()). */
|
|
318
|
+
address?: string;
|
|
319
|
+
/** Cairo version for the account contract. */
|
|
320
|
+
cairoVersion?: CairoVersion;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Create a starknet.js Account from any SignerAdapter.
|
|
324
|
+
*
|
|
325
|
+
* Bridges the gap between SignerAdapter and starknet.js Account,
|
|
326
|
+
* so you can use the Account with TxBuilder or any starknet.js API.
|
|
327
|
+
*/
|
|
328
|
+
declare function createAccount(opts: CreateAccountOptions): Promise<Account>;
|
|
329
|
+
|
|
330
|
+
interface FeeEstimate {
|
|
331
|
+
overall_fee: bigint;
|
|
332
|
+
gas_consumed: bigint;
|
|
333
|
+
gas_price: bigint;
|
|
334
|
+
data_gas_consumed?: bigint;
|
|
335
|
+
data_gas_price?: bigint;
|
|
336
|
+
}
|
|
337
|
+
interface PreflightResult {
|
|
338
|
+
transaction_trace: unknown;
|
|
339
|
+
fee_estimation: {
|
|
340
|
+
overall_fee: bigint;
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Estimate invocation fees for a set of calls.
|
|
346
|
+
* Does NOT execute the transaction.
|
|
347
|
+
*
|
|
348
|
+
* @param calls - Array of Starknet calls to estimate
|
|
349
|
+
* @param account - Starknet Account instance
|
|
350
|
+
* @throws If calls array is empty
|
|
351
|
+
*/
|
|
352
|
+
declare function estimateFee(calls: Call[], account: Account): Promise<FeeEstimate>;
|
|
353
|
+
/**
|
|
354
|
+
* Simulate a transaction without submitting it.
|
|
355
|
+
* Returns trace and fee estimation.
|
|
356
|
+
*
|
|
357
|
+
* @param calls - Array of Starknet calls to simulate
|
|
358
|
+
* @param account - Starknet Account instance
|
|
359
|
+
* @throws If calls array is empty
|
|
360
|
+
*/
|
|
361
|
+
declare function preflight(calls: Call[], account: Account): Promise<PreflightResult>;
|
|
362
|
+
|
|
363
|
+
/** SNIP-12 domain for x402 payments */
|
|
364
|
+
declare const X402_DOMAIN: {
|
|
365
|
+
name: string;
|
|
366
|
+
version: string;
|
|
367
|
+
chainId: string;
|
|
368
|
+
};
|
|
369
|
+
/** SNIP-12 typed data structure for x402 payment */
|
|
370
|
+
declare const X402_TYPES: {
|
|
371
|
+
StarknetDomain: {
|
|
372
|
+
name: string;
|
|
373
|
+
type: string;
|
|
374
|
+
}[];
|
|
375
|
+
Payment: {
|
|
376
|
+
name: string;
|
|
377
|
+
type: string;
|
|
378
|
+
}[];
|
|
379
|
+
};
|
|
380
|
+
/** Simple convenience params for buildX402TypedData */
|
|
381
|
+
interface BuildX402SimpleParams {
|
|
382
|
+
/** Sender address */
|
|
383
|
+
from: string;
|
|
384
|
+
/** Recipient address */
|
|
385
|
+
recipient: string;
|
|
386
|
+
/** Amount in USDC base units (string) */
|
|
387
|
+
amount: string;
|
|
388
|
+
/** Nonce for replay protection */
|
|
389
|
+
nonce: string;
|
|
390
|
+
/** Seconds until expiry (default: 300) */
|
|
391
|
+
expiry?: number;
|
|
392
|
+
/** Asset address (default: USDC mainnet) */
|
|
393
|
+
asset?: string;
|
|
394
|
+
}
|
|
395
|
+
/** Full message params (original API) */
|
|
396
|
+
interface BuildX402FullMessage {
|
|
397
|
+
from_address: string;
|
|
398
|
+
to_address: string;
|
|
399
|
+
amount: string;
|
|
400
|
+
asset: string;
|
|
401
|
+
valid_until: string;
|
|
402
|
+
nonce: string;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Build the full SNIP-12 typed data object for an x402 payment.
|
|
406
|
+
* Centralises the structure so client, facilitator, and React hook stay in sync.
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```typescript
|
|
410
|
+
* // Full params (original)
|
|
411
|
+
* buildX402TypedData({ from_address, to_address, amount, asset, valid_until, nonce })
|
|
412
|
+
*
|
|
413
|
+
* // Simple convenience params
|
|
414
|
+
* buildX402TypedData({ from: sender, recipient, amount, nonce, expiry: 300 })
|
|
415
|
+
* ```
|
|
416
|
+
*/
|
|
417
|
+
declare function buildX402TypedData(message: BuildX402FullMessage | BuildX402SimpleParams): TypedData;
|
|
418
|
+
/**
|
|
419
|
+
* Minimal fetch-compatible interfaces.
|
|
420
|
+
* These mirror the standard Fetch API but allow the client to work
|
|
421
|
+
* in both browser and Node.js (18+) environments without requiring DOM lib.
|
|
422
|
+
*/
|
|
423
|
+
interface FetchResponse {
|
|
424
|
+
status: number;
|
|
425
|
+
headers: {
|
|
426
|
+
get(name: string): string | null;
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* x402 payment client for Starknet.
|
|
431
|
+
*
|
|
432
|
+
* Wraps fetch calls with automatic HTTP 402 payment handling.
|
|
433
|
+
* When a server returns 402 Payment Required, the client:
|
|
434
|
+
* 1. Parses the payment requirement from the response header
|
|
435
|
+
* 2. Validates against configured limits (max amount, allowed recipients)
|
|
436
|
+
* 3. Signs a SNIP-12 typed data payment message
|
|
437
|
+
* 4. Retries the request with the signed payment in the X-PAYMENT header
|
|
438
|
+
*
|
|
439
|
+
* Works with any Starknet Account (DirectSigner, passkey, session key, external wallet).
|
|
440
|
+
* When used with a session key account, payments are fully automatic (no user interaction).
|
|
441
|
+
*/
|
|
442
|
+
declare class X402Client {
|
|
443
|
+
private readonly account;
|
|
444
|
+
private readonly config;
|
|
445
|
+
private readonly fetchFn;
|
|
446
|
+
constructor(account: Account, config?: X402ClientConfig);
|
|
447
|
+
/**
|
|
448
|
+
* Wrap a fetch call with x402 payment handling.
|
|
449
|
+
* If the server returns 402, automatically sign payment and retry.
|
|
450
|
+
*/
|
|
451
|
+
fetch(url: string, init?: Record<string, any>): Promise<FetchResponse>;
|
|
452
|
+
/**
|
|
453
|
+
* Parse PAYMENT-REQUIRED header from 402 response.
|
|
454
|
+
*/
|
|
455
|
+
parsePaymentRequired(response: FetchResponse): PaymentRequirement;
|
|
456
|
+
/**
|
|
457
|
+
* Validate payment requirement against client configuration limits.
|
|
458
|
+
* Throws if the payment would exceed maxPaymentAmount or recipient is not whitelisted.
|
|
459
|
+
*/
|
|
460
|
+
validateRequirement(requirement: PaymentRequirement): void;
|
|
461
|
+
/**
|
|
462
|
+
* Sign a SNIP-12 typed data payment message for the given requirement.
|
|
463
|
+
* Returns a PaymentPayload ready to be sent as the X-PAYMENT header.
|
|
464
|
+
*/
|
|
465
|
+
signPayment(requirement: PaymentRequirement): Promise<PaymentPayload>;
|
|
466
|
+
/**
|
|
467
|
+
* Retry the original request with the X-PAYMENT header containing the signed payment.
|
|
468
|
+
*/
|
|
469
|
+
private retryWithPayment;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* STRK20 confidential-token (privacy pool) constants and the minimal ABI
|
|
474
|
+
* fragment needed to (de)serialize pool actions.
|
|
475
|
+
*
|
|
476
|
+
* All values verified on Starknet mainnet 2026-06-27 against the official pool.
|
|
477
|
+
* The pool is StarkWare's permissionless multi-token confidential pool (STRK20,
|
|
478
|
+
* Starknet v0.14.2). We integrate it directly; we do not deploy our own.
|
|
479
|
+
*/
|
|
480
|
+
/** Official STRK20 privacy pool (Starknet mainnet). */
|
|
481
|
+
declare const POOL_ADDRESS = "0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a";
|
|
482
|
+
/** Canonical STRK token — the per-action fee is charged in STRK. */
|
|
483
|
+
declare const STRK_ADDRESS = "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d";
|
|
484
|
+
/** Flat fee per private action: 4 STRK (~0.12 USD at 0.03 USD/STRK). */
|
|
485
|
+
declare const FEE_AMOUNT: bigint;
|
|
486
|
+
/**
|
|
487
|
+
* Settlement window: a generated proof is valid for this many blocks
|
|
488
|
+
* (~20 min wall-clock at ~2.63s/block). An action must settle inside it.
|
|
489
|
+
*/
|
|
490
|
+
declare const PROOF_VALIDITY_BLOCKS = 450;
|
|
491
|
+
/**
|
|
492
|
+
* Minimal ABI fragment for the pool. Covers the action flow only:
|
|
493
|
+
* compile_actions (local view) -> apply_actions (proven invoke)
|
|
494
|
+
* plus the read helpers we need. The full pool ABI is large; we keep just
|
|
495
|
+
* what CallData needs to serialize a ClientAction[] input.
|
|
496
|
+
*/
|
|
497
|
+
declare const POOL_ABI: readonly [{
|
|
498
|
+
readonly type: "struct";
|
|
499
|
+
readonly name: "core::integer::u256";
|
|
500
|
+
readonly members: readonly [{
|
|
501
|
+
readonly name: "low";
|
|
502
|
+
readonly type: "core::integer::u128";
|
|
503
|
+
}, {
|
|
504
|
+
readonly name: "high";
|
|
505
|
+
readonly type: "core::integer::u128";
|
|
506
|
+
}];
|
|
507
|
+
}, {
|
|
508
|
+
readonly type: "struct";
|
|
509
|
+
readonly name: "privacy::actions::DepositInput";
|
|
510
|
+
readonly members: readonly [{
|
|
511
|
+
readonly name: "token";
|
|
512
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
513
|
+
}, {
|
|
514
|
+
readonly name: "amount";
|
|
515
|
+
readonly type: "core::integer::u128";
|
|
516
|
+
}];
|
|
517
|
+
}, {
|
|
518
|
+
readonly type: "struct";
|
|
519
|
+
readonly name: "privacy::actions::WithdrawInput";
|
|
520
|
+
readonly members: readonly [{
|
|
521
|
+
readonly name: "to_addr";
|
|
522
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
523
|
+
}, {
|
|
524
|
+
readonly name: "token";
|
|
525
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
526
|
+
}, {
|
|
527
|
+
readonly name: "amount";
|
|
528
|
+
readonly type: "core::integer::u128";
|
|
529
|
+
}, {
|
|
530
|
+
readonly name: "random";
|
|
531
|
+
readonly type: "core::felt252";
|
|
532
|
+
}];
|
|
533
|
+
}, {
|
|
534
|
+
readonly type: "struct";
|
|
535
|
+
readonly name: "privacy::actions::SetViewingKeyInput";
|
|
536
|
+
readonly members: readonly [{
|
|
537
|
+
readonly name: "random";
|
|
538
|
+
readonly type: "core::felt252";
|
|
539
|
+
}];
|
|
540
|
+
}, {
|
|
541
|
+
readonly type: "struct";
|
|
542
|
+
readonly name: "privacy::actions::OpenChannelInput";
|
|
543
|
+
readonly members: readonly [{
|
|
544
|
+
readonly name: "recipient_addr";
|
|
545
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
546
|
+
}, {
|
|
547
|
+
readonly name: "index";
|
|
548
|
+
readonly type: "core::integer::u32";
|
|
549
|
+
}, {
|
|
550
|
+
readonly name: "random";
|
|
551
|
+
readonly type: "core::felt252";
|
|
552
|
+
}, {
|
|
553
|
+
readonly name: "salt";
|
|
554
|
+
readonly type: "core::felt252";
|
|
555
|
+
}];
|
|
556
|
+
}, {
|
|
557
|
+
readonly type: "struct";
|
|
558
|
+
readonly name: "privacy::actions::OpenSubchannelInput";
|
|
559
|
+
readonly members: readonly [{
|
|
560
|
+
readonly name: "recipient_addr";
|
|
561
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
562
|
+
}, {
|
|
563
|
+
readonly name: "recipient_public_key";
|
|
564
|
+
readonly type: "core::felt252";
|
|
565
|
+
}, {
|
|
566
|
+
readonly name: "channel_key";
|
|
567
|
+
readonly type: "core::felt252";
|
|
568
|
+
}, {
|
|
569
|
+
readonly name: "index";
|
|
570
|
+
readonly type: "core::integer::u32";
|
|
571
|
+
}, {
|
|
572
|
+
readonly name: "token";
|
|
573
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
574
|
+
}, {
|
|
575
|
+
readonly name: "salt";
|
|
576
|
+
readonly type: "core::felt252";
|
|
577
|
+
}];
|
|
578
|
+
}, {
|
|
579
|
+
readonly type: "struct";
|
|
580
|
+
readonly name: "privacy::actions::CreateEncNoteInput";
|
|
581
|
+
readonly members: readonly [{
|
|
582
|
+
readonly name: "recipient_addr";
|
|
583
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
584
|
+
}, {
|
|
585
|
+
readonly name: "recipient_public_key";
|
|
586
|
+
readonly type: "core::felt252";
|
|
587
|
+
}, {
|
|
588
|
+
readonly name: "token";
|
|
589
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
590
|
+
}, {
|
|
591
|
+
readonly name: "amount";
|
|
592
|
+
readonly type: "core::integer::u128";
|
|
593
|
+
}, {
|
|
594
|
+
readonly name: "index";
|
|
595
|
+
readonly type: "core::integer::u32";
|
|
596
|
+
}, {
|
|
597
|
+
readonly name: "salt";
|
|
598
|
+
readonly type: "core::integer::u128";
|
|
599
|
+
}];
|
|
600
|
+
}, {
|
|
601
|
+
readonly type: "struct";
|
|
602
|
+
readonly name: "privacy::actions::CreateOpenNoteInput";
|
|
603
|
+
readonly members: readonly [{
|
|
604
|
+
readonly name: "recipient_addr";
|
|
605
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
606
|
+
}, {
|
|
607
|
+
readonly name: "recipient_public_key";
|
|
608
|
+
readonly type: "core::felt252";
|
|
609
|
+
}, {
|
|
610
|
+
readonly name: "token";
|
|
611
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
612
|
+
}, {
|
|
613
|
+
readonly name: "index";
|
|
614
|
+
readonly type: "core::integer::u32";
|
|
615
|
+
}, {
|
|
616
|
+
readonly name: "random";
|
|
617
|
+
readonly type: "core::felt252";
|
|
618
|
+
}];
|
|
619
|
+
}, {
|
|
620
|
+
readonly type: "struct";
|
|
621
|
+
readonly name: "privacy::actions::UseNoteInput";
|
|
622
|
+
readonly members: readonly [{
|
|
623
|
+
readonly name: "channel_key";
|
|
624
|
+
readonly type: "core::felt252";
|
|
625
|
+
}, {
|
|
626
|
+
readonly name: "token";
|
|
627
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
628
|
+
}, {
|
|
629
|
+
readonly name: "index";
|
|
630
|
+
readonly type: "core::integer::u32";
|
|
631
|
+
}];
|
|
632
|
+
}, {
|
|
633
|
+
readonly type: "struct";
|
|
634
|
+
readonly name: "core::array::Span::<core::felt252>";
|
|
635
|
+
readonly members: readonly [{
|
|
636
|
+
readonly name: "snapshot";
|
|
637
|
+
readonly type: "@core::array::Array::<core::felt252>";
|
|
638
|
+
}];
|
|
639
|
+
}, {
|
|
640
|
+
readonly type: "struct";
|
|
641
|
+
readonly name: "privacy::actions::InvokeExternalInput";
|
|
642
|
+
readonly members: readonly [{
|
|
643
|
+
readonly name: "contract_address";
|
|
644
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
645
|
+
}, {
|
|
646
|
+
readonly name: "calldata";
|
|
647
|
+
readonly type: "core::array::Span::<core::felt252>";
|
|
648
|
+
}];
|
|
649
|
+
}, {
|
|
650
|
+
readonly type: "enum";
|
|
651
|
+
readonly name: "privacy::actions::ClientAction";
|
|
652
|
+
readonly variants: readonly [{
|
|
653
|
+
readonly name: "SetViewingKey";
|
|
654
|
+
readonly type: "privacy::actions::SetViewingKeyInput";
|
|
655
|
+
}, {
|
|
656
|
+
readonly name: "OpenChannel";
|
|
657
|
+
readonly type: "privacy::actions::OpenChannelInput";
|
|
658
|
+
}, {
|
|
659
|
+
readonly name: "OpenSubchannel";
|
|
660
|
+
readonly type: "privacy::actions::OpenSubchannelInput";
|
|
661
|
+
}, {
|
|
662
|
+
readonly name: "CreateEncNote";
|
|
663
|
+
readonly type: "privacy::actions::CreateEncNoteInput";
|
|
664
|
+
}, {
|
|
665
|
+
readonly name: "CreateOpenNote";
|
|
666
|
+
readonly type: "privacy::actions::CreateOpenNoteInput";
|
|
667
|
+
}, {
|
|
668
|
+
readonly name: "Deposit";
|
|
669
|
+
readonly type: "privacy::actions::DepositInput";
|
|
670
|
+
}, {
|
|
671
|
+
readonly name: "UseNote";
|
|
672
|
+
readonly type: "privacy::actions::UseNoteInput";
|
|
673
|
+
}, {
|
|
674
|
+
readonly name: "Withdraw";
|
|
675
|
+
readonly type: "privacy::actions::WithdrawInput";
|
|
676
|
+
}, {
|
|
677
|
+
readonly name: "InvokeExternal";
|
|
678
|
+
readonly type: "privacy::actions::InvokeExternalInput";
|
|
679
|
+
}];
|
|
680
|
+
}, {
|
|
681
|
+
readonly type: "function";
|
|
682
|
+
readonly name: "compile_actions";
|
|
683
|
+
readonly state_mutability: "view";
|
|
684
|
+
readonly inputs: readonly [{
|
|
685
|
+
readonly name: "user_addr";
|
|
686
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
687
|
+
}, {
|
|
688
|
+
readonly name: "user_private_key";
|
|
689
|
+
readonly type: "core::felt252";
|
|
690
|
+
}, {
|
|
691
|
+
readonly name: "client_actions";
|
|
692
|
+
readonly type: "core::array::Array::<privacy::actions::ClientAction>";
|
|
693
|
+
}];
|
|
694
|
+
readonly outputs: readonly [{
|
|
695
|
+
readonly type: "core::array::Array::<privacy::actions::ServerAction>";
|
|
696
|
+
}];
|
|
697
|
+
}, {
|
|
698
|
+
readonly type: "function";
|
|
699
|
+
readonly name: "get_public_key";
|
|
700
|
+
readonly state_mutability: "view";
|
|
701
|
+
readonly inputs: readonly [{
|
|
702
|
+
readonly name: "user_addr";
|
|
703
|
+
readonly type: "core::starknet::contract_address::ContractAddress";
|
|
704
|
+
}];
|
|
705
|
+
readonly outputs: readonly [{
|
|
706
|
+
readonly type: "core::felt252";
|
|
707
|
+
}];
|
|
708
|
+
}];
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* STRK20 privacy types — the shield/unshield action inputs, the opaque
|
|
712
|
+
* compiled-actions payload, and the prover seam.
|
|
713
|
+
*/
|
|
714
|
+
/** Shield: move a public ERC20 balance into the pool. */
|
|
715
|
+
interface DepositInput {
|
|
716
|
+
/** ERC20 token address being shielded. */
|
|
717
|
+
token: string;
|
|
718
|
+
/** Raw amount in base units. */
|
|
719
|
+
amount: bigint;
|
|
720
|
+
}
|
|
721
|
+
/** Unshield: spend pool notes back out to a public address. */
|
|
722
|
+
interface WithdrawInput {
|
|
723
|
+
/** Public recipient address. */
|
|
724
|
+
toAddr: string;
|
|
725
|
+
/** ERC20 token address being unshielded. */
|
|
726
|
+
token: string;
|
|
727
|
+
/** Raw amount in base units. */
|
|
728
|
+
amount: bigint;
|
|
729
|
+
/** Per-action blinding randomness (felt). */
|
|
730
|
+
random: bigint;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Output of the local `compile_actions` view: the serialized ServerAction[]
|
|
734
|
+
* felts, ready to be passed verbatim as `apply_actions` calldata. Kept opaque
|
|
735
|
+
* on purpose — Cairo serde is symmetric, so the view's return felts are exactly
|
|
736
|
+
* the array calldata `apply_actions` expects.
|
|
737
|
+
*/
|
|
738
|
+
interface CompiledActions {
|
|
739
|
+
/** Raw felt serialization of `Array<ServerAction>` (length-prefixed). */
|
|
740
|
+
serverActions: string[];
|
|
741
|
+
}
|
|
742
|
+
/** An assembled-but-unproven invoke the prover must prove (SNIP-36). */
|
|
743
|
+
interface ProvableInvoke {
|
|
744
|
+
senderAddress: string;
|
|
745
|
+
calls: {
|
|
746
|
+
contractAddress: string;
|
|
747
|
+
entrypoint: string;
|
|
748
|
+
calldata: string[];
|
|
749
|
+
}[];
|
|
750
|
+
/** Reference block the proof is generated against. */
|
|
751
|
+
blockNumber?: number;
|
|
752
|
+
}
|
|
753
|
+
/** What a prover returns — attached to the v3 invoke via SNIP-36. */
|
|
754
|
+
interface ProveResult {
|
|
755
|
+
/** Base64 STARK proof. */
|
|
756
|
+
proof: string;
|
|
757
|
+
/** proof_facts felts folded into the SNIP-36 transaction hash. */
|
|
758
|
+
proofFacts: string[];
|
|
759
|
+
}
|
|
760
|
+
/**
|
|
761
|
+
* Prover seam. v1 mobile clients use a delegated prover (StarkWare's
|
|
762
|
+
* `snip-36-prover-backend`); the proof rides the transaction via SNIP-36 and is
|
|
763
|
+
* never part of the action calldata.
|
|
764
|
+
*/
|
|
765
|
+
interface PrivacyProver {
|
|
766
|
+
/** Generate a STARK proof for an assembled invoke. */
|
|
767
|
+
prove(invoke: ProvableInvoke): Promise<ProveResult>;
|
|
768
|
+
/** Whether this prover is wired and ready (gates the UI submit). */
|
|
769
|
+
ready(): Promise<boolean>;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Build the `SetViewingKey` ClientAction — the REQUIRED first action for a new
|
|
774
|
+
* pool user (verified on-chain: without it, Deposit/Withdraw revert
|
|
775
|
+
* `NO_REPLAY_PROTECTION`). Registers the viewing key (encrypted to the auditor)
|
|
776
|
+
* and bootstraps the account's replay-protection state.
|
|
777
|
+
*/
|
|
778
|
+
declare function setViewingKeyAction(random: bigint): CairoCustomEnum;
|
|
779
|
+
/**
|
|
780
|
+
* Build the `Deposit` ClientAction (shield). One variant is active; the rest
|
|
781
|
+
* are `undefined`, per starknet.js Cairo-enum encoding.
|
|
782
|
+
*/
|
|
783
|
+
declare function depositAction(input: DepositInput): CairoCustomEnum;
|
|
784
|
+
/** Build the `Withdraw` ClientAction (unshield). */
|
|
785
|
+
declare function withdrawAction(input: WithdrawInput): CairoCustomEnum;
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Deterministic message signed to derive the STRK20 **pool** key. Distinct from
|
|
789
|
+
* the account-key derivation so the pool key is a separate keypair, per the
|
|
790
|
+
* pool's `get_public_key` model. MUST never change (it fixes every pool key).
|
|
791
|
+
*/
|
|
792
|
+
declare const POOL_KEY_DERIVATION_MESSAGE = "CHIPI_STRK20_POOL_KEY_V1";
|
|
793
|
+
/** ASCII bytes of {@link POOL_KEY_DERIVATION_MESSAGE} for signing. */
|
|
794
|
+
declare function getPoolKeyDerivationMessage(): Uint8Array;
|
|
795
|
+
/**
|
|
796
|
+
* @deprecated OWNER-COUPLED — do not use for new wallets. Deriving the pool key
|
|
797
|
+
* from an owner signature breaks on guardian recovery (owner keys rotate, the
|
|
798
|
+
* derived key changes, old notes become unspendable — see SHHH_WALLET_VNEXT_SPEC
|
|
799
|
+
* §4). Use {@link derivePoolKeypair} with an owner-INDEPENDENT anchor instead.
|
|
800
|
+
*/
|
|
801
|
+
declare function derivePoolKeypairFromSignature(signature: Uint8Array): Promise<{
|
|
802
|
+
privateKey: string;
|
|
803
|
+
publicKey: string;
|
|
804
|
+
}>;
|
|
805
|
+
/**
|
|
806
|
+
* Derive the STRK20 **pool spending keypair** — DECOUPLED from any owner key
|
|
807
|
+
* (the recovery-stable design, SHHH_WALLET_VNEXT_SPEC §4).
|
|
808
|
+
*
|
|
809
|
+
* `anchorSecret` MUST be owner-INDEPENDENT and survive device loss: a passkey
|
|
810
|
+
* WebAuthn PRF output (synced → survives), a user recovery phrase, or a
|
|
811
|
+
* guardian-restored secret. NEVER an owner signature (that re-introduces the
|
|
812
|
+
* coupling). `seedDomainTag` is the per-wallet felt bound on-chain at
|
|
813
|
+
* `enable_shield` — mixed in so two wallets can never collide by PRF collision.
|
|
814
|
+
*
|
|
815
|
+
* pool key = SHA-256(POOL_DOMAIN || seedDomainTag(32B) || anchorSecret) → canonical.
|
|
816
|
+
* Its public key is the on-chain `privacy_commitment`.
|
|
817
|
+
*
|
|
818
|
+
* SECURITY: the private key is the spending key — client-side only, never STORED server-side (note: delegated proving includes the pool key in each proof request — see chipi-proof-provider).
|
|
819
|
+
*/
|
|
820
|
+
declare function derivePoolKeypair(params: {
|
|
821
|
+
anchorSecret: Uint8Array;
|
|
822
|
+
seedDomainTag: string | bigint;
|
|
823
|
+
}): Promise<{
|
|
824
|
+
privateKey: string;
|
|
825
|
+
publicKey: string;
|
|
826
|
+
}>;
|
|
827
|
+
/**
|
|
828
|
+
* Derive the **companion account** stark keypair — the standard SNIP-6 account
|
|
829
|
+
* that acts as the pool's `user_addr` (it has `is_valid_signature`; the SHHH
|
|
830
|
+
* wallet does not). A SEPARATE draw from the same anchor (defense in depth:
|
|
831
|
+
* companion-key compromise ≠ note theft, which needs the pool key). Full-range
|
|
832
|
+
* (a normal account key, not pool-canonical).
|
|
833
|
+
*/
|
|
834
|
+
declare function deriveCompanionKeypair(anchorSecret: Uint8Array): Promise<{
|
|
835
|
+
privateKey: string;
|
|
836
|
+
publicKey: string;
|
|
837
|
+
}>;
|
|
838
|
+
/**
|
|
839
|
+
* Counterfactual address of the companion account — deterministic from its
|
|
840
|
+
* public key + the standard OZ account class. Self-custodial: derivable on any
|
|
841
|
+
* device from the anchor; deploy is a no-op if it already exists. Store only the
|
|
842
|
+
* address (public) in the backend, never the key.
|
|
843
|
+
*/
|
|
844
|
+
declare function deriveCompanionAddress(params: {
|
|
845
|
+
publicKey: string;
|
|
846
|
+
classHash: string;
|
|
847
|
+
salt?: string;
|
|
848
|
+
}): string;
|
|
849
|
+
|
|
850
|
+
interface CompileActionsParams {
|
|
851
|
+
/** The user's pool address (separate from the Starknet account address). */
|
|
852
|
+
userAddress: string;
|
|
853
|
+
/**
|
|
854
|
+
* The user's POOL private key (not the account key).
|
|
855
|
+
*
|
|
856
|
+
* SECURITY: `compile_actions` is a Cairo view that takes the private key as an
|
|
857
|
+
* argument, so it MUST run against a local/trusted node only. Never point this
|
|
858
|
+
* at a public RPC — the key would be sent in the request.
|
|
859
|
+
*/
|
|
860
|
+
userPrivateKey: string;
|
|
861
|
+
/** Ordered ClientActions (e.g. a single Deposit, or a Withdraw). */
|
|
862
|
+
actions: CairoCustomEnum[];
|
|
863
|
+
/** Pool address override (defaults to the official mainnet pool). */
|
|
864
|
+
poolAddress?: string;
|
|
865
|
+
}
|
|
866
|
+
/**
|
|
867
|
+
* Run the pool's `compile_actions` view locally to turn ClientActions into the
|
|
868
|
+
* serialized ServerAction[] that `apply_actions` consumes.
|
|
869
|
+
*
|
|
870
|
+
* @param provider - A LOCAL/trusted provider (the private key is in calldata).
|
|
871
|
+
*/
|
|
872
|
+
declare function compileActions(provider: ProviderInterface, params: CompileActionsParams): Promise<CompiledActions>;
|
|
873
|
+
|
|
874
|
+
/** Build the `apply_actions(ServerAction[])` Call from compiled actions. */
|
|
875
|
+
declare function applyActionsCall(compiled: CompiledActions, poolAddress?: string): Call;
|
|
876
|
+
interface BuildShieldParams {
|
|
877
|
+
/** ERC20 token being shielded. */
|
|
878
|
+
token: string;
|
|
879
|
+
/** Raw amount in base units (must match the Deposit action). */
|
|
880
|
+
amount: bigint;
|
|
881
|
+
/** Output of {@link compileActions} for a single Deposit action. */
|
|
882
|
+
compiled: CompiledActions;
|
|
883
|
+
poolAddress?: string;
|
|
884
|
+
}
|
|
885
|
+
/**
|
|
886
|
+
* Build the shield (deposit) call batch: approve the pool to pull the token,
|
|
887
|
+
* then apply the compiled Deposit action. The proof is NOT in calldata — it
|
|
888
|
+
* rides the transaction via SNIP-36 and is attached at submit time.
|
|
889
|
+
*/
|
|
890
|
+
declare function buildShieldCalls(params: BuildShieldParams): Call[];
|
|
891
|
+
interface BuildUnshieldParams {
|
|
892
|
+
/** Output of {@link compileActions} for a single Withdraw action. */
|
|
893
|
+
compiled: CompiledActions;
|
|
894
|
+
poolAddress?: string;
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* Build the unshield (withdraw) call batch. The user already owns the notes
|
|
898
|
+
* being spent, so no approve is needed — just apply the compiled Withdraw.
|
|
899
|
+
*/
|
|
900
|
+
declare function buildUnshieldCalls(params: BuildUnshieldParams): Call[];
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Minimal fetch shape so the SDK does not depend on DOM lib types.
|
|
904
|
+
* Pass `globalThis.fetch` (Node 18+ / browsers) or any compatible impl.
|
|
905
|
+
*/
|
|
906
|
+
type FetchLike = (url: string, init?: {
|
|
907
|
+
method?: string;
|
|
908
|
+
headers?: Record<string, string>;
|
|
909
|
+
body?: string;
|
|
910
|
+
}) => Promise<{
|
|
911
|
+
ok: boolean;
|
|
912
|
+
status: number;
|
|
913
|
+
json(): Promise<unknown>;
|
|
914
|
+
text(): Promise<string>;
|
|
915
|
+
}>;
|
|
916
|
+
interface DelegatedProverOptions {
|
|
917
|
+
/** Base URL of the SNIP-36 proving backend (self-hosted in prod). */
|
|
918
|
+
baseUrl: string;
|
|
919
|
+
/** Path that accepts an invoke and returns { proof, proof_facts }. */
|
|
920
|
+
provePath?: string;
|
|
921
|
+
/** Health path used by {@link DelegatedProver.ready}. */
|
|
922
|
+
healthPath?: string;
|
|
923
|
+
/** Custom fetch (defaults to globalThis.fetch). */
|
|
924
|
+
fetchImpl?: FetchLike;
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Delegated prover: sends an assembled invoke to a remote
|
|
928
|
+
* `snip-36-prover-backend` and returns the STARK proof + proof_facts.
|
|
929
|
+
*
|
|
930
|
+
* For mobile, proving is too heavy on-device, so v1 uses this. Test points at
|
|
931
|
+
* StarkWare/SNF's hosted backend; prod points at our own Railway instance.
|
|
932
|
+
*/
|
|
933
|
+
declare class DelegatedProver implements PrivacyProver {
|
|
934
|
+
private readonly baseUrl;
|
|
935
|
+
private readonly provePath;
|
|
936
|
+
private readonly healthPath;
|
|
937
|
+
private readonly fetchImpl;
|
|
938
|
+
constructor(opts: DelegatedProverOptions);
|
|
939
|
+
prove(invoke: ProvableInvoke): Promise<ProveResult>;
|
|
940
|
+
ready(): Promise<boolean>;
|
|
941
|
+
}
|
|
942
|
+
/**
|
|
943
|
+
* Placeholder prover for dev/preview before the real prover is wired. Lets the
|
|
944
|
+
* full shield/unshield UI render end-to-end with the final submit disabled.
|
|
945
|
+
*/
|
|
946
|
+
declare class StubProver implements PrivacyProver {
|
|
947
|
+
prove(_invoke: ProvableInvoke): Promise<ProveResult>;
|
|
948
|
+
ready(): Promise<boolean>;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
interface ResourceBound {
|
|
952
|
+
/** Max units of the resource. */
|
|
953
|
+
maxAmount: bigint;
|
|
954
|
+
/** Max price per unit (fri). */
|
|
955
|
+
maxPricePerUnit: bigint;
|
|
956
|
+
}
|
|
957
|
+
interface ResourceBoundsV3 {
|
|
958
|
+
l1Gas: ResourceBound;
|
|
959
|
+
l2Gas: ResourceBound;
|
|
960
|
+
l1DataGas: ResourceBound;
|
|
961
|
+
}
|
|
962
|
+
interface Snip36InvokeParams {
|
|
963
|
+
/** Account that signs/pays (user for self-paid, relayer for sponsored). */
|
|
964
|
+
senderAddress: string;
|
|
965
|
+
/** The account `__execute__` calldata (felt[]). See {@link encodeExecuteCalldata}. */
|
|
966
|
+
calldata: string[];
|
|
967
|
+
/** Chain id felt (e.g. provider.getChainId() → "0x534e5f4d41494e"). */
|
|
968
|
+
chainId: string;
|
|
969
|
+
/** Sender nonce. */
|
|
970
|
+
nonce: bigint;
|
|
971
|
+
resourceBounds: ResourceBoundsV3;
|
|
972
|
+
/** Base64 STARK proof from the prover. */
|
|
973
|
+
proof: string;
|
|
974
|
+
/** proof_facts felts from the prover (empty → a standard v3 invoke). */
|
|
975
|
+
proofFacts: string[];
|
|
976
|
+
/** Defaults: tip 0, empty paymaster/deployment data, L1 DA modes. */
|
|
977
|
+
tip?: bigint;
|
|
978
|
+
paymasterData?: string[];
|
|
979
|
+
accountDeploymentData?: string[];
|
|
980
|
+
nonceDaMode?: number;
|
|
981
|
+
feeDaMode?: number;
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Compute the SNIP-36 invoke v3 transaction hash. With `proofFacts` empty this
|
|
985
|
+
* is exactly the standard Starknet v3 invoke hash; non-empty appends
|
|
986
|
+
* `poseidon(proof_facts)` as the final element of the hash chain.
|
|
987
|
+
*/
|
|
988
|
+
declare function computeSnip36InvokeHash(params: Snip36InvokeParams): bigint;
|
|
989
|
+
/** Sign a hash with a STARK private key (RFC-6979 deterministic). */
|
|
990
|
+
declare function signHash(privateKey: string, messageHash: bigint): {
|
|
991
|
+
r: string;
|
|
992
|
+
s: string;
|
|
993
|
+
};
|
|
994
|
+
/**
|
|
995
|
+
* Build the RPC `INVOKE_TXN_V3` payload extended with `proof` + `proof_facts`.
|
|
996
|
+
*
|
|
997
|
+
* SIGNING (verified on mainnet 2026-06-29): a STANDARD account validates the
|
|
998
|
+
* STANDARD v3 hash, so by default we sign the hash computed WITHOUT proof_facts
|
|
999
|
+
* — `proof_facts` rides as a payload field only, and the on-chain tx hash equals
|
|
1000
|
+
* the standard v3 hash. For a SNIP-36-aware account class that folds
|
|
1001
|
+
* `proof_facts` into `__validate__`, pass `{ signWithProofFacts: true }`.
|
|
1002
|
+
*
|
|
1003
|
+
* Returns `txHash` = the signed hash (the on-chain tx hash in the default mode).
|
|
1004
|
+
*/
|
|
1005
|
+
declare function buildSnip36InvokePayload(params: Snip36InvokeParams, privateKey: string, opts?: {
|
|
1006
|
+
signWithProofFacts?: boolean;
|
|
1007
|
+
}): {
|
|
1008
|
+
txHash: bigint;
|
|
1009
|
+
invokeTransaction: Record<string, unknown>;
|
|
1010
|
+
};
|
|
1011
|
+
/**
|
|
1012
|
+
* Build the SEQUENCER GATEWAY payload for a SNIP-36 invoke (verified on mainnet
|
|
1013
|
+
* 2026-06-29 — the shipped shield/unshield path).
|
|
1014
|
+
*
|
|
1015
|
+
* Why the gateway, not the JSON-RPC: the cartridge JSON-RPC silently DROPS the
|
|
1016
|
+
* `proof_facts` field, so the pool sees `EMPTY_PROOF_FACTS`. The sequencer
|
|
1017
|
+
* gateway is SNIP-36-aware: it keeps `proof_facts` (into tx_info) AND computes
|
|
1018
|
+
* the tx hash WITH the proof_facts hash appended — so we sign the WITH-FACTS
|
|
1019
|
+
* hash here (always), and even a STANDARD account validates it on the gateway.
|
|
1020
|
+
*
|
|
1021
|
+
* Differences from the RPC payload: `type: "INVOKE_FUNCTION"` and UPPERCASE
|
|
1022
|
+
* resource-bound keys (`L1_GAS`/`L2_GAS`/`L1_DATA_GAS`).
|
|
1023
|
+
*/
|
|
1024
|
+
declare function buildGatewayPayload(params: Snip36InvokeParams, privateKey: string): {
|
|
1025
|
+
txHash: bigint;
|
|
1026
|
+
gatewayPayload: Record<string, unknown>;
|
|
1027
|
+
};
|
|
1028
|
+
/**
|
|
1029
|
+
* Submit a SNIP-36 gateway payload to `${gatewayUrl}/gateway/add_transaction`.
|
|
1030
|
+
* Returns the transaction hash. Throws if the gateway does not return
|
|
1031
|
+
* `code: "TRANSACTION_RECEIVED"`.
|
|
1032
|
+
*/
|
|
1033
|
+
declare function submitViaGateway(gatewayUrl: string, gatewayPayload: Record<string, unknown>, fetchImpl?: (url: string, init: {
|
|
1034
|
+
method: string;
|
|
1035
|
+
headers: Record<string, string>;
|
|
1036
|
+
body: string;
|
|
1037
|
+
}) => Promise<{
|
|
1038
|
+
json(): Promise<unknown>;
|
|
1039
|
+
}>): Promise<string>;
|
|
1040
|
+
/**
|
|
1041
|
+
* Compile an account `__execute__` calldata from a list of Calls — the
|
|
1042
|
+
* `calldata` field for {@link Snip36InvokeParams}.
|
|
1043
|
+
*/
|
|
1044
|
+
declare function encodeExecuteCalldata(calls: Call[], cairoVersion?: CairoVersion): string[];
|
|
1045
|
+
/**
|
|
1046
|
+
* Submit a SNIP-36 invoke via raw JSON-RPC `starknet_addInvokeTransaction`.
|
|
1047
|
+
* Uses a raw call because the extra proof fields aren't in starknet.js's typed
|
|
1048
|
+
* invoke. Returns the transaction hash from the node.
|
|
1049
|
+
*/
|
|
1050
|
+
declare function submitSnip36Invoke(rpcUrl: string, invokeTransaction: Record<string, unknown>, fetchImpl?: (url: string, init: {
|
|
1051
|
+
method: string;
|
|
1052
|
+
headers: Record<string, string>;
|
|
1053
|
+
body: string;
|
|
1054
|
+
}) => Promise<{
|
|
1055
|
+
json(): Promise<unknown>;
|
|
1056
|
+
}>): Promise<string>;
|
|
1057
|
+
/**
|
|
1058
|
+
* Submit a SNIP-36 invoke with the sequencer GATEWAY as primary and a
|
|
1059
|
+
* SNIP-36-aware RPC as fallback.
|
|
1060
|
+
*
|
|
1061
|
+
* The feeder gateway is StarkWare-deprecated; the RPC path is the durable
|
|
1062
|
+
* successor. The RPC MUST be SNIP-36-aware (keeps `proof_facts` and computes the
|
|
1063
|
+
* with-facts hash — e.g. Alchemy/Dwellir spec v0.8+). Do NOT pass a node that
|
|
1064
|
+
* drops `proof_facts` (e.g. cartridge) — the pool would see `EMPTY_PROOF_FACTS`.
|
|
1065
|
+
* Both transports sign the WITH-FACTS hash.
|
|
1066
|
+
*
|
|
1067
|
+
* @returns the tx hash and which transport carried it.
|
|
1068
|
+
*/
|
|
1069
|
+
declare function submitSnip36WithFallback(params: Snip36InvokeParams, privateKey: string, opts: {
|
|
1070
|
+
gatewayUrl?: string;
|
|
1071
|
+
rpcUrl?: string;
|
|
1072
|
+
/** FULL submit URL used VERBATIM (no path appended) — for browser callers
|
|
1073
|
+
* that must POST through a same-origin server proxy: the sequencer
|
|
1074
|
+
* gateway sends no CORS headers, so a direct browser POST is blocked
|
|
1075
|
+
* (walletv2 ships an /api/starknet-gateway proxy for exactly this). */
|
|
1076
|
+
submitUrl?: string;
|
|
1077
|
+
fetchImpl?: (url: string, init: {
|
|
1078
|
+
method: string;
|
|
1079
|
+
headers: Record<string, string>;
|
|
1080
|
+
body: string;
|
|
1081
|
+
}) => Promise<{
|
|
1082
|
+
json(): Promise<unknown>;
|
|
1083
|
+
}>;
|
|
1084
|
+
}): Promise<{
|
|
1085
|
+
transactionHash: string;
|
|
1086
|
+
via: "gateway" | "rpc";
|
|
1087
|
+
}>;
|
|
1088
|
+
/** Convenience: the apply_actions Call's calldata is the compiled server actions. */
|
|
1089
|
+
declare function serverActionsCalldata(compiled: CompiledActions): string[];
|
|
1090
|
+
|
|
1091
|
+
/**
|
|
1092
|
+
* Proof provider that routes proving through chipi-back `/privacy/prove` (which
|
|
1093
|
+
* forwards to the private SNIP-36 prover over Railway internal networking).
|
|
1094
|
+
*
|
|
1095
|
+
* Extends the official `ProvingServiceProofProvider` so it inherits the exact
|
|
1096
|
+
* `getDefaultDetails()` the SDK's proof-invocation factory needs (replicating it
|
|
1097
|
+
* drifts — a missing field breaks tx-hash signing). We override ONLY `prove()`
|
|
1098
|
+
* to call chipi-back with auth instead of an open JSON-RPC prover. The prover
|
|
1099
|
+
* itself is never publicly reachable; access is Chipi-gated at the proxy.
|
|
1100
|
+
*/
|
|
1101
|
+
interface ChipiProofProviderOptions {
|
|
1102
|
+
/** chipi-back base URL, e.g. https://api.chipipay.com */
|
|
1103
|
+
baseUrl: string;
|
|
1104
|
+
/** Chipi API PUBLIC key — sent as `x-api-key` (chipi-back's BearerTokenGuard
|
|
1105
|
+
* requires it ALONGSIDE the JWT). Also the Authorization fallback when no
|
|
1106
|
+
* user JWT is supplied (shim / server-side callers). */
|
|
1107
|
+
apiKey: string;
|
|
1108
|
+
/** Static user JWT (Authorization: Bearer). Prefer getBearerToken. */
|
|
1109
|
+
bearerToken?: string;
|
|
1110
|
+
/** Fresh-token source called RIGHT BEFORE each prove request. The companion
|
|
1111
|
+
* deploy + approvals that precede proving take 30–90s of on-chain waits —
|
|
1112
|
+
* longer than a typical auth token's lifetime (Clerk ≈60s), so a token
|
|
1113
|
+
* captured at flow start is often expired by prove time (the live
|
|
1114
|
+
* first-attempt "prove 401: Invalid JWT", 2026-07-04). */
|
|
1115
|
+
getBearerToken?: () => Promise<string | null | undefined>;
|
|
1116
|
+
/** Chain id felt — needed for the proof-invocation defaults (e.g. SN_MAIN). */
|
|
1117
|
+
chainId: string;
|
|
1118
|
+
/** Prove endpoint path. Default "/privacy/prove". */
|
|
1119
|
+
provePath?: string;
|
|
1120
|
+
/** Reference block. Default "latest" (the prover resolves to head − N). */
|
|
1121
|
+
blockId?: string | number;
|
|
1122
|
+
/** Custom fetch (defaults to globalThis.fetch). */
|
|
1123
|
+
fetchImpl?: FetchLike;
|
|
1124
|
+
}
|
|
1125
|
+
/** The proof shape the SDK's compiler/execute consumes. */
|
|
1126
|
+
interface ProofResult {
|
|
1127
|
+
data: string;
|
|
1128
|
+
output: string[];
|
|
1129
|
+
proofFacts: string[];
|
|
1130
|
+
/** Screening attestation side-channel from a screening-capable prover
|
|
1131
|
+
* (hosted proving). Pool v2.0 REQUIRES it on deposits; the bundled SDK
|
|
1132
|
+
* packs it into apply_actions calldata when present. */
|
|
1133
|
+
additionalData?: {
|
|
1134
|
+
signature?: {
|
|
1135
|
+
issued_at: number;
|
|
1136
|
+
sig_r: string;
|
|
1137
|
+
sig_s: string;
|
|
1138
|
+
};
|
|
1139
|
+
};
|
|
1140
|
+
}
|
|
1141
|
+
interface ProofInvocation {
|
|
1142
|
+
sender_address: string;
|
|
1143
|
+
[k: string]: unknown;
|
|
1144
|
+
}
|
|
1145
|
+
declare class ChipiProofProvider extends ProvingServiceProofProvider {
|
|
1146
|
+
private readonly chipiBaseUrl;
|
|
1147
|
+
private readonly apiKey;
|
|
1148
|
+
private readonly chipiBearer?;
|
|
1149
|
+
private readonly chipiGetBearer?;
|
|
1150
|
+
private readonly chipiProvePath;
|
|
1151
|
+
private readonly chipiBlockId;
|
|
1152
|
+
private readonly chipiFetch;
|
|
1153
|
+
constructor(opts: ChipiProofProviderOptions);
|
|
1154
|
+
prove(invocation: ProofInvocation, blockIdentifier?: string | number): Promise<ProofResult>;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
interface ShieldFee {
|
|
1158
|
+
/** Pool privacy fee in STRK (wei) — `collect_fee` charges this to the caller. */
|
|
1159
|
+
feeStrk: bigint;
|
|
1160
|
+
/** Same fee in USD, given a STRK/USD price. What the user actually sees. */
|
|
1161
|
+
feeUsd: number;
|
|
1162
|
+
}
|
|
1163
|
+
/**
|
|
1164
|
+
* The STRK20 pool charges a FIXED STRK fee per op (`collect_fee`, 4 STRK). The
|
|
1165
|
+
* consumer UX must NEVER make the user hold STRK (the Ready model): the
|
|
1166
|
+
* paymaster / gas-tank FRONTS the STRK, and we surface the cost in USD. This
|
|
1167
|
+
* converts the on-chain STRK fee to the USD figure for the review screen.
|
|
1168
|
+
*/
|
|
1169
|
+
declare function getShieldFee(strkUsdPrice: number, feeAmount?: bigint): ShieldFee;
|
|
1170
|
+
/**
|
|
1171
|
+
* Review-screen preview (mirrors Ready's `−10 USDC → +9.86 [USDC], 0.14 fee`).
|
|
1172
|
+
*
|
|
1173
|
+
* - `sponsored: true` (recommended for adoption): the gas-tank eats the fee, the
|
|
1174
|
+
* user receives the FULL amount (`received === amount`).
|
|
1175
|
+
* - otherwise: the USD-equivalent fee is deducted from the shielded amount, so
|
|
1176
|
+
* `received = amount − feeInToken` (the deducted token reimburses the fronted STRK).
|
|
1177
|
+
*
|
|
1178
|
+
* `amount` and `received` are in token wei (e.g. USDC at 6 decimals).
|
|
1179
|
+
*/
|
|
1180
|
+
declare function previewShield(params: {
|
|
1181
|
+
amount: bigint;
|
|
1182
|
+
tokenDecimals: number;
|
|
1183
|
+
tokenUsdPrice: number;
|
|
1184
|
+
strkUsdPrice: number;
|
|
1185
|
+
sponsored?: boolean;
|
|
1186
|
+
}): {
|
|
1187
|
+
received: bigint;
|
|
1188
|
+
feeInToken: bigint;
|
|
1189
|
+
feeStrk: bigint;
|
|
1190
|
+
feeUsd: number;
|
|
1191
|
+
};
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* High-level shield / unshield over the official (vendored) StarkWare privacy
|
|
1195
|
+
* SDK + our prover proxy + the sequencer gateway. This is the packaged,
|
|
1196
|
+
* verified path (mainnet 2026-06-29: shield 0x31f84064…, unshield 0x78fe9dd5…).
|
|
1197
|
+
*
|
|
1198
|
+
* The note-graph (compile_actions, channel/note crypto, discovery) comes from
|
|
1199
|
+
* the vendored `starknet-sdk`; proving goes through {@link ChipiProofProvider}
|
|
1200
|
+
* (chipi-back → private prover); submit uses {@link submitSnip36WithFallback}
|
|
1201
|
+
* (gateway primary, SNIP-36-aware RPC fallback). Every call WAITS for the
|
|
1202
|
+
* receipt and asserts it settled ({@link assertShieldReceipt}) — no phantom
|
|
1203
|
+
* success on a mere gateway-accept.
|
|
1204
|
+
*
|
|
1205
|
+
* Fee model (the Ready model): the pool charges a fixed STRK fee (`collect_fee`,
|
|
1206
|
+
* 4 STRK) to the caller. The user NEVER holds STRK — the paymaster/gas-tank
|
|
1207
|
+
* FRONTS the STRK into the companion, and the cost is surfaced in USD via
|
|
1208
|
+
* {@link getShieldFee}/{@link previewShield}. `ShieldResult.feeStrk` is the
|
|
1209
|
+
* incurred pool fee.
|
|
1210
|
+
*
|
|
1211
|
+
* Preconditions (the gasless funding step handles both): the companion must hold
|
|
1212
|
+
* the ~4 STRK fee (fronted) and have approved the pool for the deposit amount.
|
|
1213
|
+
*/
|
|
1214
|
+
|
|
1215
|
+
/** The account/pool context shared by every privacy op (shield, unshield, balance). */
|
|
1216
|
+
interface PrivacyContext {
|
|
1217
|
+
provider: RpcProvider;
|
|
1218
|
+
/** The pool `user_addr`: a standard SNIP-6 account (companion or native vNext). */
|
|
1219
|
+
account: Account;
|
|
1220
|
+
/** Pool spending key — DECOUPLED from owner keys, PRF-anchored (see SHHH vNext spec §4). */
|
|
1221
|
+
viewingKey: bigint;
|
|
1222
|
+
provingProvider: ChipiProofProvider;
|
|
1223
|
+
poolAddress?: string;
|
|
1224
|
+
}
|
|
1225
|
+
interface ShieldParams extends PrivacyContext {
|
|
1226
|
+
/** Private key used to sign the SNIP-36 gateway tx (the account's signer key). */
|
|
1227
|
+
signerKey: string;
|
|
1228
|
+
token: string;
|
|
1229
|
+
amount: bigint;
|
|
1230
|
+
gatewayUrl?: string;
|
|
1231
|
+
/** FULL submit URL used verbatim — browser same-origin proxy for the
|
|
1232
|
+
* CORS-less sequencer gateway (see submitSnip36WithFallback.submitUrl). */
|
|
1233
|
+
gatewaySubmitUrl?: string;
|
|
1234
|
+
/** SNIP-36-aware RPC fallback (Alchemy/Dwellir v0.8+) if the gateway is down/deprecated. */
|
|
1235
|
+
rpcUrl?: string;
|
|
1236
|
+
chainId: string;
|
|
1237
|
+
}
|
|
1238
|
+
/** Receipt or the Error waitForTransaction may throw. */
|
|
1239
|
+
interface ShieldReceiptLike {
|
|
1240
|
+
execution_status?: string;
|
|
1241
|
+
finality_status?: string;
|
|
1242
|
+
revert_reason?: string;
|
|
1243
|
+
events?: {
|
|
1244
|
+
from_address?: string;
|
|
1245
|
+
}[];
|
|
1246
|
+
message?: string;
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Anti-phantom-success guard. The gateway returning TRANSACTION_RECEIVED only
|
|
1250
|
+
* means accepted — the tx can still REVERT (proof expiry, NEGATIVE_INTERMEDIATE
|
|
1251
|
+
* _BALANCE, etc.). Assert the receipt actually SUCCEEDED *and* the pool emitted
|
|
1252
|
+
* an event (proof verified + state changed), not just that a hash exists.
|
|
1253
|
+
*/
|
|
1254
|
+
declare function assertShieldReceipt(r: ShieldReceiptLike, poolAddress: string): void;
|
|
1255
|
+
interface ShieldResult {
|
|
1256
|
+
transactionHash: string;
|
|
1257
|
+
via: "gateway" | "rpc";
|
|
1258
|
+
receipt: ShieldReceiptLike;
|
|
1259
|
+
/** Pool fee incurred (STRK wei) — fronted by the gas-tank, shown to the user in USD. */
|
|
1260
|
+
feeStrk: bigint;
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Read the user's private (shielded) balance per token by scanning notes with
|
|
1264
|
+
* their viewing key. Discovery only — no proving, no on-chain write, safe to
|
|
1265
|
+
* call for display. Returns per-token totals keyed by lowercase hex address.
|
|
1266
|
+
*/
|
|
1267
|
+
declare function getPrivateBalance(p: PrivacyContext & {
|
|
1268
|
+
tokens?: string[];
|
|
1269
|
+
}): Promise<{
|
|
1270
|
+
byToken: Record<string, bigint>;
|
|
1271
|
+
}>;
|
|
1272
|
+
/**
|
|
1273
|
+
* Shield SEVERAL tokens in ONE apply_actions — one proof, one pool fee.
|
|
1274
|
+
* Uses the SDK's `with(token, ops)` callback overload (returns `this`),
|
|
1275
|
+
* which exists precisely for batched multi-token builds.
|
|
1276
|
+
*/
|
|
1277
|
+
declare function shieldMany(p: Omit<ShieldParams, "token" | "amount"> & {
|
|
1278
|
+
deposits: {
|
|
1279
|
+
token: string;
|
|
1280
|
+
amount: bigint;
|
|
1281
|
+
}[];
|
|
1282
|
+
}): Promise<ShieldResult>;
|
|
1283
|
+
/** Shield `amount` of `token` from the account into a private note. */
|
|
1284
|
+
declare function shield(p: ShieldParams): Promise<ShieldResult>;
|
|
1285
|
+
/** Unshield `amount` of `token` from private notes back to the account. */
|
|
1286
|
+
declare function unshield(p: ShieldParams): Promise<ShieldResult>;
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Auto-shield ("Recibir en privado") — automatically shield incoming deposits.
|
|
1290
|
+
*
|
|
1291
|
+
* This layer is PURE POLICY: it decides *whether* and *how much* to shield for a
|
|
1292
|
+
* deposit, then delegates the actual shield to a caller-supplied executor. It is
|
|
1293
|
+
* deliberately account-agnostic so it survives the v8.5 shift unchanged:
|
|
1294
|
+
* - TODAY (companion): the executor builds ShieldParams with the companion
|
|
1295
|
+
* account + its derived signer key.
|
|
1296
|
+
* - v8.5 (native SHHH): the executor builds ShieldParams with the SHHH wallet
|
|
1297
|
+
* as user_addr + a relayer/OE submit. Same call site; only the executor's
|
|
1298
|
+
* account wiring changes. NO change to this policy layer.
|
|
1299
|
+
*/
|
|
1300
|
+
type AutoShieldMode = "off" | "cross-chain" | "all";
|
|
1301
|
+
interface PrivacySettings {
|
|
1302
|
+
/** "Recibir en privado" master. */
|
|
1303
|
+
autoShield: AutoShieldMode;
|
|
1304
|
+
/**
|
|
1305
|
+
* Do not auto-shield dust (fee would dominate). In token wei. Deposits below
|
|
1306
|
+
* this are left in the available balance. Default applied by resolveAutoShield.
|
|
1307
|
+
*/
|
|
1308
|
+
minAmount?: bigint;
|
|
1309
|
+
}
|
|
1310
|
+
type DepositSource = "cross-chain" | "onchain" | "internal";
|
|
1311
|
+
interface DepositEvent {
|
|
1312
|
+
/** Token contract (felt hex). */
|
|
1313
|
+
token: string;
|
|
1314
|
+
/** Amount that arrived (token wei). */
|
|
1315
|
+
amount: bigint;
|
|
1316
|
+
/** Where it came from — drives the "solo cross-chain" default. */
|
|
1317
|
+
source: DepositSource;
|
|
1318
|
+
/** The arrival tx (for idempotency + notifications). */
|
|
1319
|
+
txHash: string;
|
|
1320
|
+
/** Token decimals, for display. */
|
|
1321
|
+
tokenDecimals?: number;
|
|
1322
|
+
}
|
|
1323
|
+
type AutoShieldDecision = {
|
|
1324
|
+
shield: true;
|
|
1325
|
+
amount: bigint;
|
|
1326
|
+
reason: "cross-chain" | "all";
|
|
1327
|
+
} | {
|
|
1328
|
+
shield: false;
|
|
1329
|
+
reason: "disabled" | "source-excluded" | "below-min";
|
|
1330
|
+
};
|
|
1331
|
+
/**
|
|
1332
|
+
* Decide whether a deposit should be auto-shielded. Pure — no I/O, fully
|
|
1333
|
+
* testable. `cross-chain` mode shields only bridged/cross-chain inflows (the
|
|
1334
|
+
* killer case: fewer, larger, privacy-worthy); `all` shields every deposit.
|
|
1335
|
+
*/
|
|
1336
|
+
declare function resolveAutoShield(deposit: DepositEvent, settings: PrivacySettings): AutoShieldDecision;
|
|
1337
|
+
interface AutoShieldOutcome {
|
|
1338
|
+
decision: AutoShieldDecision;
|
|
1339
|
+
/** Present only when a shield was executed. */
|
|
1340
|
+
result?: ShieldResult;
|
|
1341
|
+
/** Present when the executor threw (shield failed — deposit stays available). */
|
|
1342
|
+
error?: string;
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Run the auto-shield policy for a deposit and, if it decides to shield, invoke
|
|
1346
|
+
* `executeShield` (which owns the account wiring — companion today, native v8.5
|
|
1347
|
+
* tomorrow). `isAlreadyShielded` provides idempotency: a redelivered deposit
|
|
1348
|
+
* event (webhooks retry) must not double-shield.
|
|
1349
|
+
*/
|
|
1350
|
+
declare function autoShieldOnDeposit(params: {
|
|
1351
|
+
deposit: DepositEvent;
|
|
1352
|
+
settings: PrivacySettings;
|
|
1353
|
+
executeShield: (token: string, amount: bigint) => Promise<ShieldResult>;
|
|
1354
|
+
isAlreadyShielded?: (txHash: string) => Promise<boolean>;
|
|
1355
|
+
}): Promise<AutoShieldOutcome>;
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Companion-account orchestration for shield/unshield — the PRODUCTION path
|
|
1359
|
+
* battle-tested in walletv2 (2026-07-04→06 live-money QA) and backported here
|
|
1360
|
+
* so the SDK is the single engine.
|
|
1361
|
+
*
|
|
1362
|
+
* A "companion" is a lightweight standard account, counterfactual until first
|
|
1363
|
+
* use, derived from the user's anchor (see keys.ts). It is the pool
|
|
1364
|
+
* `user_addr` (SNIP-6 `is_valid_signature`) and self-pays gas from STRK the
|
|
1365
|
+
* gas-tank fronts (see gas.ts) — the USER never holds STRK.
|
|
1366
|
+
*
|
|
1367
|
+
* Order of operations (each step idempotent, learned the hard way):
|
|
1368
|
+
* 1. deploy the companion if it isn't on-chain (self-paid, salt = pubkey);
|
|
1369
|
+
* 2. approve the pool for the deposit token (the note-graph SDK proves
|
|
1370
|
+
* apply_actions in isolation — a missing allowance passes proving under
|
|
1371
|
+
* SKIP_VALIDATE then reverts on-chain as an opaque "Result::unwrap
|
|
1372
|
+
* failed");
|
|
1373
|
+
* 3. approve STRK for the pool's collect_fee (same masked-revert trap);
|
|
1374
|
+
* 4. shield()/unshield() — prove + gateway submit + receipt assert.
|
|
1375
|
+
*
|
|
1376
|
+
* Transient RPC errors (the public fee-estimation backend intermittently
|
|
1377
|
+
* refuses connections) retry with backoff; real reverts never do.
|
|
1378
|
+
*/
|
|
1379
|
+
|
|
1380
|
+
/** Retry clearly-transient network/infra errors only — never a real revert. */
|
|
1381
|
+
declare function withTransientRetry<T>(fn: () => Promise<T>, opts?: {
|
|
1382
|
+
tries?: number;
|
|
1383
|
+
delayMs?: number;
|
|
1384
|
+
}): Promise<T>;
|
|
1385
|
+
interface CompanionCtx {
|
|
1386
|
+
provider: RpcProvider;
|
|
1387
|
+
chainId: string;
|
|
1388
|
+
/** Counterfactual companion address (deriveCompanionAddress). */
|
|
1389
|
+
companionAddress: string;
|
|
1390
|
+
/** Companion signer private key (deriveCompanionKeypair). NEVER a server value. */
|
|
1391
|
+
companionKey: string;
|
|
1392
|
+
/** Companion account class hash (standard SNIP-6 account, e.g. OZ). */
|
|
1393
|
+
classHash: string;
|
|
1394
|
+
/** Pool spending/viewing key (derivePoolKeypair). */
|
|
1395
|
+
poolKey: bigint;
|
|
1396
|
+
provingProvider: ChipiProofProvider;
|
|
1397
|
+
poolAddress?: string;
|
|
1398
|
+
gatewayUrl?: string;
|
|
1399
|
+
/** Browser same-origin proxy for the CORS-less sequencer gateway. */
|
|
1400
|
+
gatewaySubmitUrl?: string;
|
|
1401
|
+
/** SNIP-36-aware RPC fallback. */
|
|
1402
|
+
rpcUrl?: string;
|
|
1403
|
+
}
|
|
1404
|
+
/**
|
|
1405
|
+
* Deploy the companion if it isn't on-chain yet (counterfactual → live).
|
|
1406
|
+
* Self-pays from the companion's STRK (gas-tank-fronted BEFORE this runs).
|
|
1407
|
+
* Idempotent; salt = pubkey so deployed address == counterfactual address.
|
|
1408
|
+
*/
|
|
1409
|
+
declare function ensureCompanionDeployed(c: CompanionCtx): Promise<void>;
|
|
1410
|
+
/**
|
|
1411
|
+
* Approve `spender-pool` for `amount` of `token` from the companion —
|
|
1412
|
+
* SETTLED ON-CHAIN before proving (see module doc). Idempotent: skips when
|
|
1413
|
+
* the live allowance already covers `amount`.
|
|
1414
|
+
*/
|
|
1415
|
+
declare function ensureApproval(c: CompanionCtx, token: string, amount: bigint): Promise<void>;
|
|
1416
|
+
/** STRK allowance for collect_fee: the fixed fee + 50% buffer. */
|
|
1417
|
+
declare const FEE_APPROVE_STRK: bigint;
|
|
1418
|
+
/** Full production shield: deploy → approvals → prove/submit/assert. */
|
|
1419
|
+
declare function execShield(c: CompanionCtx, token: string, amount: bigint): Promise<ShieldResult>;
|
|
1420
|
+
/**
|
|
1421
|
+
* Multi-token production shield: ONE proof, ONE pool fee for N tokens.
|
|
1422
|
+
* Approvals settle per token BEFORE proving (same masked-revert trap as the
|
|
1423
|
+
* single-token path). MAINNET-PROVEN 2026-07-08 (S5 smoke): USDC+STRK in one
|
|
1424
|
+
* apply_actions 0x56f93116…, exactly one 4-STRK fee, per-token unshields OK.
|
|
1425
|
+
* NOTE the prover-view constraint: proving runs against head-12, so notes/
|
|
1426
|
+
* approvals created moments ago are invisible for ~6 min — back-to-back ops
|
|
1427
|
+
* must wait (see scripts/*-token-smoke.mjs waitProverView).
|
|
1428
|
+
*/
|
|
1429
|
+
declare function execShieldMany(c: CompanionCtx, deposits: {
|
|
1430
|
+
token: string;
|
|
1431
|
+
amount: bigint;
|
|
1432
|
+
}[]): Promise<ShieldResult>;
|
|
1433
|
+
/**
|
|
1434
|
+
* Full production unshield: deploy → STRK fee re-approve → prove/submit/assert.
|
|
1435
|
+
* (No token approve: funds come FROM the pool.) Withdraws to the COMPANION —
|
|
1436
|
+
* the caller delivers onward (sweepCompanion) so the money lands in the
|
|
1437
|
+
* user's real wallet, not the internal account.
|
|
1438
|
+
*/
|
|
1439
|
+
declare function execUnshield(c: CompanionCtx, token: string, amount: bigint): Promise<ShieldResult>;
|
|
1440
|
+
|
|
1441
|
+
/**
|
|
1442
|
+
* Gas-tank funding + companion hygiene — the "user never holds STRK" half of
|
|
1443
|
+
* the Ready fee model, backported from walletv2's production path.
|
|
1444
|
+
*
|
|
1445
|
+
* • requestGasFunding — asks chipi-back /privacy/fund-gas to front STRK
|
|
1446
|
+
* into the companion (deploy gas + the pool's fixed fee). Fetches a FRESH
|
|
1447
|
+
* auth token per attempt and retries 401 (stale JWT) and 5xx (the
|
|
1448
|
+
* backend's transient RPC/nonce errors — live 503s killed shields on
|
|
1449
|
+
* 2026-07-05 before retries existed on either side).
|
|
1450
|
+
* • waitForFunding — fund txs resolve on SUBMIT, not confirmation; poll
|
|
1451
|
+
* until the companion actually holds the STRK (+ token for a shield) so
|
|
1452
|
+
* deploy/shield don't fail with "exceed balance (0)".
|
|
1453
|
+
* • sweepCompanion — after an op, deliver withdrawn tokens to the user's
|
|
1454
|
+
* wallet and return leftover fronted STRK to the gas tank (the tank
|
|
1455
|
+
* fronts ~13 STRK but a shield burns ~7.4; without the sweep ~5.6 STRK
|
|
1456
|
+
* strands per op). Pure call-building is exposed for tests.
|
|
1457
|
+
*/
|
|
1458
|
+
|
|
1459
|
+
/** STRK fronted per op: pool fee + measured deploy/approve/tx-gas headroom
|
|
1460
|
+
* (mainnet 0x24dde8c…: ~7.4 STRK burned, gateway validates ~8 STRK of max
|
|
1461
|
+
* resource bounds — 13 clears validation; the sweep recovers the surplus). */
|
|
1462
|
+
declare const GAS_FUND_STRK: bigint;
|
|
1463
|
+
/** STRK kept in the companion by the sweep, to pay the sweep tx itself. */
|
|
1464
|
+
declare const SWEEP_RESERVE_STRK: bigint;
|
|
1465
|
+
interface GasFundingOptions {
|
|
1466
|
+
/** chipi-back base URL, e.g. https://api.chipipay.com/v1 */
|
|
1467
|
+
baseUrl: string;
|
|
1468
|
+
/** Chipi API public key (x-api-key header — required alongside the JWT). */
|
|
1469
|
+
apiKey: string;
|
|
1470
|
+
/** Static JWT fallback. Prefer getBearerToken. */
|
|
1471
|
+
bearerToken?: string;
|
|
1472
|
+
/** Fresh-token source, called before EVERY attempt. */
|
|
1473
|
+
getBearerToken?: () => Promise<string | null | undefined>;
|
|
1474
|
+
/** Fund-gas path. Default "/privacy/fund-gas". */
|
|
1475
|
+
fundGasPath?: string;
|
|
1476
|
+
/** Retry backoff base (ms). Tests inject 0. */
|
|
1477
|
+
retryDelayMs?: number;
|
|
1478
|
+
fetchImpl?: FetchLike;
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Front `amountStrk` (wei; default {@link GAS_FUND_STRK}) from the Chipi
|
|
1482
|
+
* gas-tank into `companion`. Resolves on SUBMIT — pair with waitForFunding.
|
|
1483
|
+
*/
|
|
1484
|
+
declare function requestGasFunding(companion: string, opts: GasFundingOptions & {
|
|
1485
|
+
amountStrk?: bigint;
|
|
1486
|
+
}): Promise<void>;
|
|
1487
|
+
/**
|
|
1488
|
+
* Poll until the companion holds ≥ needStrk STRK (and ≥ needToken of `token`
|
|
1489
|
+
* when provided). Throws "funding_timeout" past the deadline.
|
|
1490
|
+
*/
|
|
1491
|
+
declare function waitForFunding(provider: RpcProvider, companion: string, need: {
|
|
1492
|
+
strk: bigint;
|
|
1493
|
+
token?: {
|
|
1494
|
+
address: string;
|
|
1495
|
+
amount: bigint;
|
|
1496
|
+
};
|
|
1497
|
+
}, opts?: {
|
|
1498
|
+
timeoutMs?: number;
|
|
1499
|
+
pollMs?: number;
|
|
1500
|
+
}): Promise<void>;
|
|
1501
|
+
interface SweepCall {
|
|
1502
|
+
contractAddress: string;
|
|
1503
|
+
entrypoint: "transfer";
|
|
1504
|
+
calldata: [string, string, string];
|
|
1505
|
+
}
|
|
1506
|
+
/**
|
|
1507
|
+
* PURE: the transfers a sweep should execute given live balances. Exposed for
|
|
1508
|
+
* tests — the on-chain wrapper is {@link sweepCompanion}.
|
|
1509
|
+
*/
|
|
1510
|
+
declare function buildSweepCalls(p: {
|
|
1511
|
+
tokenBalances: {
|
|
1512
|
+
address: string;
|
|
1513
|
+
amount: bigint;
|
|
1514
|
+
deliverTo?: string;
|
|
1515
|
+
}[];
|
|
1516
|
+
strkBalance: bigint;
|
|
1517
|
+
gasTank: string;
|
|
1518
|
+
reserve?: bigint;
|
|
1519
|
+
}): SweepCall[];
|
|
1520
|
+
/**
|
|
1521
|
+
* Post-op sweep: deliver `deliverToken` (if any) to the user's wallet and
|
|
1522
|
+
* return leftover STRK (minus the reserve) to the gas tank. One companion tx,
|
|
1523
|
+
* self-paid. BEST-EFFORT by design: a transient failure never blocks the op —
|
|
1524
|
+
* funds stay safe in the companion and the next op/recovery reclaims them.
|
|
1525
|
+
*/
|
|
1526
|
+
declare function sweepCompanion(p: {
|
|
1527
|
+
provider: RpcProvider;
|
|
1528
|
+
companionAddress: string;
|
|
1529
|
+
companionKey: string;
|
|
1530
|
+
gasTank: string;
|
|
1531
|
+
/** Deliver this token's full companion balance to `to` (unshield delivery). */
|
|
1532
|
+
deliverToken?: {
|
|
1533
|
+
address: string;
|
|
1534
|
+
to: string;
|
|
1535
|
+
};
|
|
1536
|
+
/** Throw instead of swallowing errors — REQUIRED when the sweep IS the
|
|
1537
|
+
* delivery of the user's money (unshield), review finding M2. Best-effort
|
|
1538
|
+
* remains the default for the background STRK-return case. */
|
|
1539
|
+
strict?: boolean;
|
|
1540
|
+
}): Promise<{
|
|
1541
|
+
transactionHash: string | null;
|
|
1542
|
+
}>;
|
|
1543
|
+
|
|
1544
|
+
export { Amount, type AutoShieldDecision, type AutoShieldMode, type AutoShieldOutcome, type BuildShieldParams, type BuildUnshieldParams, type BuildX402SimpleParams, ChipiProofProvider, type ChipiProofProviderOptions, type CompanionCtx, type CompileActionsParams, type CompiledActions, type CreateAccountOptions, DelegatedProver, type DelegatedProverOptions, type DepositEvent, type DepositInput, type DepositSource, DirectSigner, Erc20, ExternalSigner, FEE_AMOUNT, FEE_APPROVE_STRK, type FeeEstimate, type FetchLike, GAS_FUND_STRK, type GasFundingOptions, type Network, POOL_ABI, POOL_ADDRESS, POOL_KEY_DERIVATION_MESSAGE, PROOF_VALIDITY_BLOCKS, PasskeySigner, type PreflightResult$1 as PreflightResult, type PrivacyContext, type PrivacyProver, type PrivacySettings, type ProofResult, type ProvableInvoke, type ProveResult, type ResourceBound, type ResourceBoundsV3, STRK_ADDRESS, SWEEP_RESERVE_STRK, type ShieldFee, type ShieldParams, type ShieldReceiptLike, type ShieldResult, type SignResult, type SignerAdapter, type Snip36InvokeParams, StarknetSignerAdapter, StubProver, type SweepCall, type TokenInfo, TokenRegistry, type TransferTarget, TxBuilder, type TxBuilderOptions, type WithdrawInput, X402Client, X402_DOMAIN, X402_TYPES, applyActionsCall, assertShieldReceipt, autoShieldOnDeposit, buildGatewayPayload, buildShieldCalls, buildSnip36InvokePayload, buildSweepCalls, buildUnshieldCalls, buildX402TypedData, compileActions, computeSnip36InvokeHash, createAccount, depositAction, deriveCompanionAddress, deriveCompanionKeypair, derivePoolKeypair, derivePoolKeypairFromSignature, encodeExecuteCalldata, ensureApproval, ensureCompanionDeployed, estimateFee, execShield, execShieldMany, execUnshield, getPoolKeyDerivationMessage, getPrivateBalance, getShieldFee, preflight, previewShield, requestGasFunding, resolveAutoShield, serverActionsCalldata, setViewingKeyAction, shield, shieldMany, signHash, submitSnip36Invoke, submitSnip36WithFallback, submitViaGateway, sweepCompanion, unshield, waitForFunding, withTransientRetry, withdrawAction };
|