@chipi-stack/chipi-react 14.4.0 → 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.mts +430 -3
- package/dist/hooks.d.ts +430 -3
- package/dist/hooks.js +162 -0
- package/dist/hooks.js.map +1 -1
- package/dist/hooks.mjs +160 -2
- package/dist/hooks.mjs.map +1 -1
- package/dist/index.d.mts +78 -4
- package/dist/index.d.ts +78 -4
- package/dist/index.js +331 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +329 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -5
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
|
-
|
|
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;
|