@chipi-stack/chipi-react 14.3.1 → 14.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/dist/hooks.d.ts CHANGED
@@ -1,6 +1,7 @@
1
- import { CreateWalletParams, CreateWalletResponse, GetWalletParams, GetWalletResponse, ChainToken, GetTokenBalanceResponse, WalletType, WalletData, SessionKeyData, SessionDataResponse, CreateSessionKeyParams, SessionConfig, Call, SpendingPolicyConfig, SpendingPolicyData, MigrateWalletToPasskeyParams, UpdateWalletEncryptionParams, UpdateWalletEncryptionResponse, TransferHookInput, ApproveHookInput, GetTransactionListQuery, PaginatedResponse, Transaction, TransactionStatusResponse, SyncOnChainTransfersParams, SyncOnChainTransfersResponse, CreateSkuPurchaseParams, GetSkuListQuery, Sku, CallAnyContractParams, RecordSendTransactionParams, GetTokenBalanceParams, AddSessionKeyParams, RevokeSessionKeyParams, GetSessionDataParams, ExecuteWithSessionParams, PaymentRequirement, PaymentPayload } from '@chipi-stack/types';
1
+ import { CreateWalletParams, CreateWalletResponse, GetWalletParams, GetWalletResponse, ChainToken, GetTokenBalanceResponse, WalletType, WalletData, SessionKeyData, SessionDataResponse, CreateSessionKeyParams, SessionConfig, Call as Call$1, SpendingPolicyConfig, SpendingPolicyData, MigrateWalletToPasskeyParams, UpdateWalletEncryptionParams, UpdateWalletEncryptionResponse, TransferHookInput, ApproveHookInput, GetTransactionListQuery, PaginatedResponse, Transaction, TransactionStatusResponse, SyncOnChainTransfersParams, SyncOnChainTransfersResponse, CreateSkuPurchaseParams, GetSkuListQuery, Sku, CallAnyContractParams, RecordSendTransactionParams, GetTokenBalanceParams, AddSessionKeyParams, RevokeSessionKeyParams, GetSessionDataParams, ExecuteWithSessionParams, PaymentRequirement, PaymentPayload } from '@chipi-stack/types';
2
2
  import * as _tanstack_react_query from '@tanstack/react-query';
3
3
  import { UseQueryOptions, UseQueryResult } from '@tanstack/react-query';
4
+ import { MigrateChipiWalletToShhhParams, MigrationOutcome, Eip191Pubkey, WebAuthnPubkey, JwtAppleSubPubkey, NewOwnerInput, buildProposeAddOwnerCall, TIMELOCK_SECONDS, DEFAULT_OP_EXPIRY_SECONDS, ROLE_OWNER, ROLE_GUARDIAN, OP_ADD_OWNER, OP_REMOVE_OWNER, OP_ROTATE_OWNER, OP_SET_THRESHOLD, ShhhSignerKind, MIN_THRESHOLD_OWNERS } from '@chipi-stack/backend';
4
5
 
5
6
  type CreateWalletInput = {
6
7
  params: CreateWalletParams;
@@ -386,7 +387,7 @@ interface UseChipiSessionReturn {
386
387
  /** Revoke the current session from the blockchain */
387
388
  revokeSession: () => Promise<string>;
388
389
  /** Execute calls using the session key (no owner signature needed) */
389
- executeWithSession: (calls: Call[]) => Promise<string>;
390
+ executeWithSession: (calls: Call$1[]) => Promise<string>;
390
391
  /** Clear the current session from local state */
391
392
  clearSession: () => void;
392
393
  /** Refresh the on-chain session status */
@@ -521,6 +522,82 @@ declare function useUpdateWalletEncryption(): {
521
522
  reset: () => void;
522
523
  };
523
524
 
525
+ /**
526
+ * Input for the migration mutation.
527
+ *
528
+ * Drops `client` and `bearerToken` from the SDK-level params (the
529
+ * hook reads them from context + the input below) and treats the
530
+ * rest the same as the SDK call. The hook does NOT touch passkey /
531
+ * PIN orchestration — callers are responsible for handing in the
532
+ * already-resolved `encryptKey`. For the dashboard flow this means
533
+ * showing the PIN/passkey prompt yourself and passing the result
534
+ * here.
535
+ */
536
+ type MigrateInput = Omit<MigrateChipiWalletToShhhParams, "client" | "bearerToken"> & {
537
+ bearerToken: string;
538
+ };
539
+ /**
540
+ * Hook for migrating a CHIPI v29 wallet to SHHH V8.4.
541
+ *
542
+ * Wraps the `migrateChipiWalletToShhh` backend SDK function (which
543
+ * itself composes chipi-back's prepare + execute endpoints with
544
+ * client-side V8.4 OE signing). The PIN/passkey unwrap step happens
545
+ * before this hook is called; the migration multicall is signed
546
+ * locally with the resulting STARK key and the cleartext key never
547
+ * leaves the device.
548
+ *
549
+ * Two terminal outcomes the consumer must handle:
550
+ * - `{ kind: "MIGRATED", transactionHash, ... }` — happy path,
551
+ * on-chain tx landed and DB row is patched. If `partial: true`,
552
+ * the on-chain tx succeeded but the chipi-back DB patch failed;
553
+ * the operator runbook's reconciler cron (task #30) will catch
554
+ * up automatically. Dashboard should surface "wallet upgraded;
555
+ * refresh in a moment" copy in both sub-cases.
556
+ * - `{ kind: "ALREADY_MIGRATED", primaryKind, ... }` — chipi-back
557
+ * detected the wallet was already SHHH on chain and patched the
558
+ * DB row on the way out. No on-chain tx fired. Dashboard should
559
+ * surface "this wallet is already on V8.4" and refresh the
560
+ * wallet shape.
561
+ *
562
+ * Throws (surfaces via `error`) on:
563
+ * - STRANDED-state recovery (different signing flow, not in PR A)
564
+ * - UNDEPLOYED wallets (caller should redirect to createWallet)
565
+ * - DEFERRED legacy versions (v28/v33; not yet supported)
566
+ * - Mismatched encryptKey (decryption fails)
567
+ * - chipi-back kill switch off (`CHIPI_MIGRATION_ENABLED` not set)
568
+ *
569
+ * @example
570
+ * ```tsx
571
+ * const { migrateAsync, isLoading, error } = useMigrateWalletToShhh();
572
+ *
573
+ * async function onClickMigrate() {
574
+ * const encryptKey = await promptForPin(); // or passkey unlock
575
+ * const outcome = await migrateAsync({
576
+ * walletId: wallet.id,
577
+ * externalUserId: user.id,
578
+ * wallet: { publicKey: wallet.publicKey, encryptedPrivateKey: wallet.encryptedPrivateKey },
579
+ * encryptKey,
580
+ * bearerToken,
581
+ * });
582
+ * if (outcome.kind === "MIGRATED") {
583
+ * showToast(`Wallet upgraded — tx ${outcome.transactionHash}`);
584
+ * } else {
585
+ * showToast(`Wallet was already on V8.4 (${outcome.primaryKind})`);
586
+ * }
587
+ * }
588
+ * ```
589
+ */
590
+ declare function useMigrateWalletToShhh(): {
591
+ migrate: (input: MigrateInput) => void;
592
+ migrateAsync: (input: MigrateInput) => Promise<MigrationOutcome>;
593
+ data: MigrationOutcome | undefined;
594
+ isLoading: boolean;
595
+ isError: boolean;
596
+ error: Error | null;
597
+ isSuccess: boolean;
598
+ reset: () => void;
599
+ };
600
+
524
601
  type TransferInput = {
525
602
  params: TransferHookInput;
526
603
  bearerToken: string;
@@ -2189,4 +2266,354 @@ interface UseX402PaymentReturn {
2189
2266
  */
2190
2267
  declare function useX402Payment(config: UseX402PaymentConfig): UseX402PaymentReturn;
2191
2268
 
2192
- export { type ChipiWalletData, type SessionState, type SessionWallet, type UseChipiSessionConfig, type UseChipiSessionReturn, type UseChipiWalletConfig, type UseChipiWalletReturn, type UseTransferConfig, type UseX402PaymentConfig, type UseX402PaymentReturn, useAddSessionKeyToContract, useApprove, useCallAnyContract, useChipiSession, useChipiWallet, useCreateSessionKey, useCreateWallet, useExecuteWithSession, useGetSessionData, useGetSku, useGetSkuList, useGetSkuPurchase, useGetTokenBalance, useGetTransaction, useGetTransactionList, useGetTransactionStatus, useGetWallet, useMigrateWalletToPasskey, usePurchaseSku, useRecordSendTransaction, useRevokeSessionKey, useSyncOnChainTransfers, useTransfer, useUpdateWalletEncryption, useX402Payment };
2269
+ /**
2270
+ * SHHH V8.4 envelope builders surfaced as a single hook for React
2271
+ * integrators. Each helper returns the `signature: felt252[]` span
2272
+ * ready to pass to `paymaster_executeSponsoredRaw.calldata`.
2273
+ *
2274
+ * Most helpers take the OE `messageHash` plus kind-specific inputs.
2275
+ * `signWithMetaMask` is the exception: the `messageHash` is already
2276
+ * baked into the user-signed payload upstream, so it takes only the
2277
+ * 65-byte `personal_sign` signature and the registered pubkey.
2278
+ *
2279
+ * The hook is intentionally a thin facade over the
2280
+ * `@chipi-stack/backend` builders: it adds semantic names that map
2281
+ * to the user-facing wallet (`signWithMetaMask` = EIP-191,
2282
+ * `signWithPhantom` = Ed25519, `signWithPasskey` = WebAuthn P-256)
2283
+ * and stable React refs, but does NOT do browser-glue (no
2284
+ * `window.ethereum`, `window.solana`, or `navigator.credentials.get`
2285
+ * calls). Integrators retain full control of the user-prompt step:
2286
+ *
2287
+ * 1. Integrator calls their wallet adapter to get the raw signature
2288
+ * (or assertion / id_token).
2289
+ * 2. Integrator passes that into the matching helper to wrap it into
2290
+ * the V2_SNIP12 envelope.
2291
+ *
2292
+ * Pair with `useGuardianRecovery` or `useThresholdSign` (B6/B7) for
2293
+ * on-chain execution flows that need the recovery/governance builders.
2294
+ */
2295
+ interface UseShhhSignerReturn {
2296
+ /**
2297
+ * STARK ECDSA signer (legacy CHIPI v29 keys, fastest path).
2298
+ * Pure-local: no wallet prompt.
2299
+ */
2300
+ signWithStark: (params: {
2301
+ privateKey: bigint | string;
2302
+ messageHash: bigint;
2303
+ }) => bigint[];
2304
+ /**
2305
+ * Phantom-shape Ed25519 signer (Solana users importing to Starknet).
2306
+ * The 32-byte private key is the Solana keypair's secret material;
2307
+ * the public key is recovered inside the builder.
2308
+ */
2309
+ signWithPhantom: (params: {
2310
+ privateKey: Uint8Array;
2311
+ messageHash: bigint;
2312
+ }) => Promise<bigint[]>;
2313
+ /**
2314
+ * MetaMask-shape EIP-191 (`personal_sign`) signer. The signature
2315
+ * MUST come from a `personal_sign` over the 32-byte big-endian
2316
+ * messageHash; the pubkey was registered at wallet creation time.
2317
+ */
2318
+ signWithMetaMask: (params: {
2319
+ signatureHex: string;
2320
+ pubkey: Eip191Pubkey;
2321
+ }) => bigint[];
2322
+ /**
2323
+ * WebAuthn P-256 signer (passkey). Takes a completed
2324
+ * `navigator.credentials.get()` assertion split into its three
2325
+ * fields (authenticatorData, clientDataJSON, signature DER) plus
2326
+ * the pubkey registered at credential creation time.
2327
+ */
2328
+ signWithPasskey: (params: {
2329
+ authenticatorData: Uint8Array;
2330
+ clientDataJSON: Uint8Array;
2331
+ signatureDer: Uint8Array;
2332
+ pubkey: WebAuthnPubkey;
2333
+ messageHash: bigint;
2334
+ yParity?: 0n | 1n;
2335
+ }) => bigint[];
2336
+ /**
2337
+ * Apple Sign In signer (`JWT_ES256_APPLE_SUB`). Takes the
2338
+ * `id_token` from Apple's OAuth response. The nonce claim MUST
2339
+ * encode `messageHash` (see `messageHashToNonceB64url`).
2340
+ */
2341
+ signWithAppleIdToken: (params: {
2342
+ idToken: string;
2343
+ pubkey: JwtAppleSubPubkey;
2344
+ messageHash: bigint;
2345
+ }) => bigint[];
2346
+ }
2347
+ declare function useShhhSigner(): UseShhhSignerReturn;
2348
+
2349
+ type Call = ReturnType<typeof buildProposeAddOwnerCall>;
2350
+ /**
2351
+ * SHHH V8.4 multi-owner governance + guardian-recovery builders
2352
+ * surfaced as a single React hook. Each helper returns a Starknet
2353
+ * `Call` object (NOT a signature envelope); callers compose those
2354
+ * calls into an OutsideExecution and submit them via the paymaster
2355
+ * adapter, signing the OE with `useShhhSigner`.
2356
+ *
2357
+ * Two top-level flows are intended:
2358
+ *
2359
+ * 1. ADD DEVICE (user has wallet access, wants a second owner)
2360
+ * a. `proposeAddOwner` (owner-signed OE)
2361
+ * b. wait 48h timelock
2362
+ * c. `executeAddOwner` (owner-signed OE, with the opId from 1a)
2363
+ *
2364
+ * 2. RECOVER VIA GUARDIAN (user lost key)
2365
+ * a. `initiateRecovery` (guardian-signed OE)
2366
+ * b. wait 7 days
2367
+ * c. `finalizeRecovery` (anyone can submit, no signature required
2368
+ * beyond Cairo-side state checks)
2369
+ *
2370
+ * Read-only timelock helpers (`isReady`, `secondsRemaining`) take a
2371
+ * `validAfter` timestamp pulled from chain state and a clock reading;
2372
+ * they don't query the chain themselves. Pair this hook with whatever
2373
+ * mechanism your app already uses for on-chain state reads
2374
+ * (`useGetWallet`, RPC, multicall, etc.).
2375
+ *
2376
+ * The full controlled-component `<Recover />` route that wires this
2377
+ * hook into a state machine + UI ships as B6.2.
2378
+ */
2379
+ interface UseGuardianRecoveryReturn {
2380
+ buildProposeAddOwner: (args: {
2381
+ walletAddress: bigint | string;
2382
+ proposer: number;
2383
+ newOwner: NewOwnerInput;
2384
+ }) => Call;
2385
+ buildExecuteAddOwner: (args: {
2386
+ walletAddress: bigint | string;
2387
+ opId: bigint | string;
2388
+ newOwner: NewOwnerInput;
2389
+ }) => Call;
2390
+ buildProposeRemoveOwner: (args: {
2391
+ walletAddress: bigint | string;
2392
+ proposer: number;
2393
+ ownerId: number;
2394
+ }) => Call;
2395
+ buildExecuteRemoveOwner: (args: {
2396
+ walletAddress: bigint | string;
2397
+ opId: bigint | string;
2398
+ ownerId: number;
2399
+ }) => Call;
2400
+ buildProposeRotateOwner: (args: {
2401
+ walletAddress: bigint | string;
2402
+ proposer: number;
2403
+ ownerId: number;
2404
+ newPubkeyBytes: bigint[];
2405
+ }) => Call;
2406
+ buildExecuteRotateOwner: (args: {
2407
+ walletAddress: bigint | string;
2408
+ opId: bigint | string;
2409
+ ownerId: number;
2410
+ newPubkeyBytes: bigint[];
2411
+ }) => Call;
2412
+ buildProposeSetThreshold: (args: {
2413
+ walletAddress: bigint | string;
2414
+ proposer: number;
2415
+ newThreshold: number;
2416
+ }) => Call;
2417
+ buildExecuteSetThreshold: (args: {
2418
+ walletAddress: bigint | string;
2419
+ opId: bigint | string;
2420
+ newThreshold: number;
2421
+ }) => Call;
2422
+ buildCancelPendingOp: (args: {
2423
+ walletAddress: bigint | string;
2424
+ opId: bigint | string;
2425
+ }) => Call;
2426
+ buildInitiateRecovery: (args: {
2427
+ walletAddress: bigint | string;
2428
+ /** owner_id of the guardian that's signing the initiation OE */
2429
+ proposer: number;
2430
+ newOwner: NewOwnerInput;
2431
+ }) => Call;
2432
+ buildCancelRecovery: (args: {
2433
+ walletAddress: bigint | string;
2434
+ ownerId: number;
2435
+ }) => Call;
2436
+ buildFinalizeRecovery: (args: {
2437
+ walletAddress: bigint | string;
2438
+ newOwner: NewOwnerInput;
2439
+ }) => Call;
2440
+ isReady: (validAfterSecs: number | bigint, nowSecs?: number) => boolean;
2441
+ secondsRemaining: (validAfterSecs: number | bigint, nowSecs?: number) => number;
2442
+ TIMELOCK_SECONDS: typeof TIMELOCK_SECONDS;
2443
+ DEFAULT_OP_EXPIRY_SECONDS: typeof DEFAULT_OP_EXPIRY_SECONDS;
2444
+ ROLE_OWNER: typeof ROLE_OWNER;
2445
+ ROLE_GUARDIAN: typeof ROLE_GUARDIAN;
2446
+ OP_ADD_OWNER: typeof OP_ADD_OWNER;
2447
+ OP_REMOVE_OWNER: typeof OP_REMOVE_OWNER;
2448
+ OP_ROTATE_OWNER: typeof OP_ROTATE_OWNER;
2449
+ OP_SET_THRESHOLD: typeof OP_SET_THRESHOLD;
2450
+ }
2451
+ declare function useGuardianRecovery(): UseGuardianRecoveryReturn;
2452
+
2453
+ /**
2454
+ * SHHH V8.4 N-of-M threshold sign coordinator surfaced as a React
2455
+ * hook. Two complementary surfaces:
2456
+ *
2457
+ * 1. **Stateless helpers** — `assemble`, `parse`, and
2458
+ * `estimateGasOverhead` are pure facades over the matching
2459
+ * `@chipi-stack/backend` builders. Use them when you already
2460
+ * have all the inner envelopes in one render and just want to
2461
+ * ship the final V2_THRESHOLD span.
2462
+ *
2463
+ * 2. **Stateful collector** — for UI flows where N owners sign
2464
+ * asynchronously (passkey on phone → MetaMask on laptop, agent
2465
+ * auto-co-signing while a human reviews, etc.) the hook keeps
2466
+ * a queue of collected inner envelopes, exposes a "X of N
2467
+ * signed" state for UI display, validates each new envelope at
2468
+ * add-time (duplicate owner_id detection, structural shape),
2469
+ * and assembles the final span once the threshold is met via
2470
+ * `finalize()`.
2471
+ *
2472
+ * The collector validates each envelope inline using
2473
+ * `assertValidV2Snip12Envelope` from the backend — the same check the
2474
+ * `buildThresholdEnvelope` builder runs at assembly time. That way an
2475
+ * integrator's UI can show "owner 3 envelope rejected: duplicate
2476
+ * owner_id" before submitting the V2_THRESHOLD span on chain, instead
2477
+ * of after the paymaster reverts.
2478
+ *
2479
+ * Threshold governance (`propose_set_threshold` / `execute_set_threshold`)
2480
+ * lives in `useGuardianRecovery` because the multi-owner signing
2481
+ * here and the threshold-change proposals there share the same
2482
+ * Cairo SHHH wallet but are operationally separate flows.
2483
+ */
2484
+ interface UseThresholdSignReturn {
2485
+ /**
2486
+ * Assemble an N-of-M V2_THRESHOLD envelope from a pre-collected
2487
+ * list of inner V2_SNIP12 envelopes. Pure; no internal state used.
2488
+ * Throws on duplicate owner_id, structural mismatch, or negative
2489
+ * felts — same validation the on-chain dispatch would apply.
2490
+ */
2491
+ assemble: (args: {
2492
+ innerEnvelopes: bigint[][];
2493
+ }) => bigint[];
2494
+ /**
2495
+ * Inverse of `assemble`. Re-derives the constituent inner envelopes
2496
+ * from a V2_THRESHOLD span. Useful for UI flows showing "owners X,
2497
+ * Y, Z signed" from a stored envelope without re-walking the
2498
+ * collection state.
2499
+ */
2500
+ parse: (args: {
2501
+ envelope: bigint[];
2502
+ }) => {
2503
+ innerEnvelopes: bigint[][];
2504
+ };
2505
+ /**
2506
+ * Sum the per-kind paymaster gas overhead across the owners that
2507
+ * will participate. Use this to surface "this 2-of-3 mixed-kind
2508
+ * tx will cost X l2_gas to verify" copy in a UI.
2509
+ *
2510
+ * Per [services/gasless/signer-kinds#gas-overhead], a STARK +
2511
+ * EIP-191 pair budgets 2M + 10M = 12M l2_gas for verification on
2512
+ * top of the call's own cost.
2513
+ */
2514
+ estimateGasOverhead: (args: {
2515
+ owners: Array<{
2516
+ signerKind: ShhhSignerKind;
2517
+ }>;
2518
+ }) => number;
2519
+ /**
2520
+ * Live state machine. Re-renders the consuming component when an
2521
+ * envelope is added, removed, or the collection is reset.
2522
+ */
2523
+ state: ThresholdSignState;
2524
+ /**
2525
+ * Add one owner's inner V2_SNIP12 envelope to the collection.
2526
+ * Validates structurally + checks duplicate owner_id against
2527
+ * already-collected envelopes.
2528
+ *
2529
+ * Returns `true` on success, `false` on rejection. On rejection
2530
+ * the failure reason lands on `state.error` for inline UI display;
2531
+ * the collection is NOT mutated. A subsequent successful add
2532
+ * clears `state.error`.
2533
+ *
2534
+ * Idempotent in the sense that a second add of an already-rejected
2535
+ * envelope produces the same error; an already-collected envelope
2536
+ * (same owner_id) is treated as a duplicate.
2537
+ */
2538
+ addEnvelope: (envelope: bigint[]) => boolean;
2539
+ /**
2540
+ * Drop a previously-added envelope by its owner_id. Useful when
2541
+ * an owner signs but the integrator's review UI rejects their
2542
+ * specific tx and needs to ask them to re-sign with corrected
2543
+ * payload.
2544
+ */
2545
+ removeEnvelope: (ownerId: bigint) => void;
2546
+ /** Clear the entire collection (cancel + restart the sign flow). */
2547
+ reset: () => void;
2548
+ /**
2549
+ * Assemble the final V2_THRESHOLD envelope from collected inner
2550
+ * envelopes. Throws if fewer than `threshold` have been collected
2551
+ * (with a clear error so the caller's UI knows to keep prompting).
2552
+ */
2553
+ finalize: () => bigint[];
2554
+ MIN_THRESHOLD_OWNERS: typeof MIN_THRESHOLD_OWNERS;
2555
+ }
2556
+ interface ThresholdSignState {
2557
+ /** Threshold N this flow is collecting toward. */
2558
+ threshold: number;
2559
+ /** Inner envelopes collected so far, in arrival order. */
2560
+ collected: bigint[][];
2561
+ /**
2562
+ * Owner ids that have signed, in arrival order. Pre-derived from
2563
+ * `collected` so the UI doesn't have to re-parse each envelope.
2564
+ */
2565
+ signedOwnerIds: bigint[];
2566
+ /** Has the threshold been met? `collected.length >= threshold`. */
2567
+ isReady: boolean;
2568
+ /**
2569
+ * The most recent validation error from `addEnvelope`, if any.
2570
+ * Cleared on successful add or `reset()`. Use for inline UI error
2571
+ * display ("Owner X already signed", "envelope is malformed").
2572
+ */
2573
+ error: Error | null;
2574
+ }
2575
+ interface UseThresholdSignOptions {
2576
+ /**
2577
+ * Threshold N this flow targets. Must be at least
2578
+ * `MIN_THRESHOLD_OWNERS` (2). Changes to this value after first
2579
+ * render are honored — `isReady` re-evaluates against the new N
2580
+ * without dropping already-collected envelopes (use `reset` if
2581
+ * you need to start over).
2582
+ */
2583
+ threshold: number;
2584
+ }
2585
+ /**
2586
+ * SHHH V8.4 threshold sign coordinator.
2587
+ *
2588
+ * @example Pure assembly (all envelopes ready in one render)
2589
+ *
2590
+ * ```tsx
2591
+ * const t = useThresholdSign({ threshold: 2 });
2592
+ * const envelope = t.assemble({
2593
+ * innerEnvelopes: [starkInner, eip191Inner],
2594
+ * });
2595
+ * await submitThroughPaymaster(envelope);
2596
+ * ```
2597
+ *
2598
+ * @example Async sign flow (owners sign one at a time)
2599
+ *
2600
+ * ```tsx
2601
+ * const t = useThresholdSign({ threshold: 2 });
2602
+ *
2603
+ * // After owner 1 signs:
2604
+ * t.addEnvelope(owner1Envelope);
2605
+ *
2606
+ * // After owner 2 signs:
2607
+ * t.addEnvelope(owner2Envelope);
2608
+ *
2609
+ * // UI shows "Signed by: owner_id_1, owner_id_2" via t.state.signedOwnerIds.
2610
+ * // When t.state.isReady is true, submit:
2611
+ * if (t.state.isReady) {
2612
+ * const envelope = t.finalize();
2613
+ * await submitThroughPaymaster(envelope);
2614
+ * }
2615
+ * ```
2616
+ */
2617
+ declare function useThresholdSign(opts: UseThresholdSignOptions): UseThresholdSignReturn;
2618
+
2619
+ export { type ChipiWalletData, type SessionState, type SessionWallet, type ThresholdSignState, type UseChipiSessionConfig, type UseChipiSessionReturn, type UseChipiWalletConfig, type UseChipiWalletReturn, type UseGuardianRecoveryReturn, type UseShhhSignerReturn, type UseThresholdSignOptions, type UseThresholdSignReturn, type UseTransferConfig, type UseX402PaymentConfig, type UseX402PaymentReturn, useAddSessionKeyToContract, useApprove, useCallAnyContract, useChipiSession, useChipiWallet, useCreateSessionKey, useCreateWallet, useExecuteWithSession, useGetSessionData, useGetSku, useGetSkuList, useGetSkuPurchase, useGetTokenBalance, useGetTransaction, useGetTransactionList, useGetTransactionStatus, useGetWallet, useGuardianRecovery, useMigrateWalletToPasskey, useMigrateWalletToShhh, usePurchaseSku, useRecordSendTransaction, useRevokeSessionKey, useShhhSigner, useSyncOnChainTransfers, useThresholdSign, useTransfer, useUpdateWalletEncryption, useX402Payment };
package/dist/hooks.js CHANGED
@@ -666,6 +666,25 @@ function useUpdateWalletEncryption() {
666
666
  reset: mutation.reset
667
667
  };
668
668
  }
669
+ function useMigrateWalletToShhh() {
670
+ const { chipiSDK } = useChipiContext();
671
+ const mutation = reactQuery.useMutation({
672
+ mutationFn: async (input) => {
673
+ const { bearerToken, ...rest } = input;
674
+ return chipiSDK.wallets.migrateToShhh(rest, bearerToken);
675
+ }
676
+ });
677
+ return {
678
+ migrate: mutation.mutate,
679
+ migrateAsync: mutation.mutateAsync,
680
+ data: mutation.data,
681
+ isLoading: mutation.isPending,
682
+ isError: mutation.isError,
683
+ error: mutation.error,
684
+ isSuccess: mutation.isSuccess,
685
+ reset: mutation.reset
686
+ };
687
+ }
669
688
  function useTransfer(config) {
670
689
  const { chipiSDK, passkeyAdapter } = useChipiContext();
671
690
  const mutation = reactQuery.useMutation({
@@ -1551,6 +1570,145 @@ function useX402Payment(config) {
1551
1570
  paymentCount
1552
1571
  };
1553
1572
  }
1573
+ function useShhhSigner() {
1574
+ return react.useMemo(
1575
+ () => ({
1576
+ signWithStark: (params) => backend.buildStarkEnvelope({
1577
+ privateKey: params.privateKey,
1578
+ messageHash: params.messageHash
1579
+ }),
1580
+ signWithPhantom: (params) => backend.buildEd25519Envelope({
1581
+ privateKey: params.privateKey,
1582
+ messageHash: params.messageHash
1583
+ }),
1584
+ signWithMetaMask: (params) => backend.buildEip191EnvelopeFromSignature({
1585
+ signatureHex: params.signatureHex,
1586
+ pubkey: params.pubkey
1587
+ }),
1588
+ signWithPasskey: (params) => backend.buildWebAuthnEnvelopeFromAssertion({
1589
+ authenticatorData: params.authenticatorData,
1590
+ clientDataJSON: params.clientDataJSON,
1591
+ signatureDer: params.signatureDer,
1592
+ pubkey: params.pubkey,
1593
+ messageHash: params.messageHash,
1594
+ yParity: params.yParity ?? 0n
1595
+ }),
1596
+ signWithAppleIdToken: (params) => backend.buildJwtAppleSubEnvelopeFromTokenResponse({
1597
+ idToken: params.idToken,
1598
+ pubkey: params.pubkey,
1599
+ messageHash: params.messageHash
1600
+ })
1601
+ }),
1602
+ []
1603
+ );
1604
+ }
1605
+ function useGuardianRecovery() {
1606
+ return react.useMemo(
1607
+ () => ({
1608
+ buildProposeAddOwner: (args) => backend.buildProposeAddOwnerCall(args),
1609
+ buildExecuteAddOwner: (args) => backend.buildExecuteAddOwnerCall(args),
1610
+ buildProposeRemoveOwner: (args) => backend.buildProposeRemoveOwnerCall(args),
1611
+ buildExecuteRemoveOwner: (args) => backend.buildExecuteRemoveOwnerCall(args),
1612
+ buildProposeRotateOwner: (args) => backend.buildProposeRotateOwnerCall(args),
1613
+ buildExecuteRotateOwner: (args) => backend.buildExecuteRotateOwnerCall(args),
1614
+ buildProposeSetThreshold: (args) => backend.buildProposeSetThresholdCall(args),
1615
+ buildExecuteSetThreshold: (args) => backend.buildExecuteSetThresholdCall(args),
1616
+ buildCancelPendingOp: (args) => backend.buildCancelPendingOpCall(args),
1617
+ buildInitiateRecovery: (args) => backend.buildInitiateRecoveryCall(args),
1618
+ buildCancelRecovery: (args) => backend.buildCancelRecoveryCall(args),
1619
+ buildFinalizeRecovery: (args) => backend.buildFinalizeRecoveryCall(args),
1620
+ isReady: (validAfterSecs, nowSecs) => backend.isReadyToExecute(validAfterSecs, nowSecs ?? Math.floor(Date.now() / 1e3)),
1621
+ secondsRemaining: (validAfterSecs, nowSecs) => backend.secondsUntilExecutable(validAfterSecs, nowSecs ?? Math.floor(Date.now() / 1e3)),
1622
+ TIMELOCK_SECONDS: backend.TIMELOCK_SECONDS,
1623
+ DEFAULT_OP_EXPIRY_SECONDS: backend.DEFAULT_OP_EXPIRY_SECONDS,
1624
+ ROLE_OWNER: backend.ROLE_OWNER,
1625
+ ROLE_GUARDIAN: backend.ROLE_GUARDIAN,
1626
+ OP_ADD_OWNER: backend.OP_ADD_OWNER,
1627
+ OP_REMOVE_OWNER: backend.OP_REMOVE_OWNER,
1628
+ OP_ROTATE_OWNER: backend.OP_ROTATE_OWNER,
1629
+ OP_SET_THRESHOLD: backend.OP_SET_THRESHOLD
1630
+ }),
1631
+ []
1632
+ );
1633
+ }
1634
+ function useThresholdSign(opts) {
1635
+ const { threshold } = opts;
1636
+ const [collected, setCollected] = react.useState([]);
1637
+ const [signedOwnerIds, setSignedOwnerIds] = react.useState([]);
1638
+ const [error, setError] = react.useState(null);
1639
+ const signedOwnerIdsRef = react.useRef([]);
1640
+ const addEnvelope = react.useCallback((envelope) => {
1641
+ let ownerId;
1642
+ try {
1643
+ ownerId = backend.assertValidV2Snip12Envelope(envelope);
1644
+ } catch (e) {
1645
+ const err = e instanceof Error ? e : new Error(String(e));
1646
+ setError(err);
1647
+ return false;
1648
+ }
1649
+ if (signedOwnerIdsRef.current.some((id) => id === ownerId)) {
1650
+ const err = new Error(
1651
+ `THRESH: owner_id 0x${ownerId.toString(16)} has already signed; use removeEnvelope first if you want to replace their envelope.`
1652
+ );
1653
+ setError(err);
1654
+ return false;
1655
+ }
1656
+ signedOwnerIdsRef.current = [...signedOwnerIdsRef.current, ownerId];
1657
+ setCollected((prev) => [...prev, envelope]);
1658
+ setSignedOwnerIds(signedOwnerIdsRef.current);
1659
+ setError(null);
1660
+ return true;
1661
+ }, []);
1662
+ const removeEnvelope = react.useCallback((ownerId) => {
1663
+ const matchIndex = signedOwnerIdsRef.current.findIndex((id) => id === ownerId);
1664
+ if (matchIndex < 0) return;
1665
+ signedOwnerIdsRef.current = signedOwnerIdsRef.current.filter((id) => id !== ownerId);
1666
+ setCollected((prev) => prev.filter((_, i) => i !== matchIndex));
1667
+ setSignedOwnerIds(signedOwnerIdsRef.current);
1668
+ setError(null);
1669
+ }, []);
1670
+ const reset = react.useCallback(() => {
1671
+ signedOwnerIdsRef.current = [];
1672
+ setCollected([]);
1673
+ setSignedOwnerIds([]);
1674
+ setError(null);
1675
+ }, []);
1676
+ const finalize = react.useCallback(() => {
1677
+ if (collected.length < threshold) {
1678
+ throw new Error(
1679
+ `THRESH: cannot finalize \u2014 need ${threshold} envelopes, have ${collected.length}. Wait for more owners to sign.`
1680
+ );
1681
+ }
1682
+ return backend.buildThresholdEnvelope({ innerEnvelopes: collected });
1683
+ }, [collected, threshold]);
1684
+ const state = react.useMemo(
1685
+ () => ({
1686
+ threshold,
1687
+ collected,
1688
+ signedOwnerIds,
1689
+ isReady: collected.length >= threshold,
1690
+ error
1691
+ }),
1692
+ [threshold, collected, signedOwnerIds, error]
1693
+ );
1694
+ const stateless = react.useMemo(
1695
+ () => ({
1696
+ assemble: (args) => backend.buildThresholdEnvelope(args),
1697
+ parse: (args) => backend.parseThresholdEnvelope(args.envelope),
1698
+ estimateGasOverhead: (args) => backend.estimateThresholdGasOverhead(args.owners),
1699
+ MIN_THRESHOLD_OWNERS: backend.MIN_THRESHOLD_OWNERS
1700
+ }),
1701
+ []
1702
+ );
1703
+ return {
1704
+ ...stateless,
1705
+ state,
1706
+ addEnvelope,
1707
+ removeEnvelope,
1708
+ reset,
1709
+ finalize
1710
+ };
1711
+ }
1554
1712
 
1555
1713
  exports.useAddSessionKeyToContract = useAddSessionKeyToContract;
1556
1714
  exports.useApprove = useApprove;
@@ -1569,11 +1727,15 @@ exports.useGetTransaction = useGetTransaction;
1569
1727
  exports.useGetTransactionList = useGetTransactionList;
1570
1728
  exports.useGetTransactionStatus = useGetTransactionStatus;
1571
1729
  exports.useGetWallet = useGetWallet;
1730
+ exports.useGuardianRecovery = useGuardianRecovery;
1572
1731
  exports.useMigrateWalletToPasskey = useMigrateWalletToPasskey;
1732
+ exports.useMigrateWalletToShhh = useMigrateWalletToShhh;
1573
1733
  exports.usePurchaseSku = usePurchaseSku;
1574
1734
  exports.useRecordSendTransaction = useRecordSendTransaction;
1575
1735
  exports.useRevokeSessionKey = useRevokeSessionKey;
1736
+ exports.useShhhSigner = useShhhSigner;
1576
1737
  exports.useSyncOnChainTransfers = useSyncOnChainTransfers;
1738
+ exports.useThresholdSign = useThresholdSign;
1577
1739
  exports.useTransfer = useTransfer;
1578
1740
  exports.useUpdateWalletEncryption = useUpdateWalletEncryption;
1579
1741
  exports.useX402Payment = useX402Payment;