@unlink-xyz/react 0.1.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 ADDED
@@ -0,0 +1,9 @@
1
+ # @unlink-xyz/react
2
+
3
+ React hooks for building private transaction applications with Unlink.
4
+
5
+ ## Overview
6
+
7
+ Provides wallet management, account handling, private transfers, and withdrawals with automatic state synchronization via React hooks and context. Wraps `@unlink-xyz/core` for React 18/19 applications.
8
+
9
+ > **Documentation:** [React guide](../../docs/sdk/react.mdx) | [API reference](../../docs/sdk/api-reference.mdx)
@@ -0,0 +1,552 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ import { ReactNode } from 'react';
3
+ import { BrowserWalletOptions, Environment, UnlinkWallet, AccountInfo, Account, NoteRecord, HistoryStatus, TransferResult, TransferPlanResult, DepositRelayResult, WithdrawalInput, WithdrawResult, WithdrawPlanResult, RelayState, HistoryEntry } from '@unlink-xyz/core';
4
+ export { Account, AccountInfo, Chain, HistoryEntry, NoteRecord, ParsedZkAddress, TransferPlanResult, TransferResult, TxStatusChangedEvent, UnlinkWallet, WalletSDKEvent, WithdrawPlanResult, WithdrawResult, computeBalances, decodeAddress, encodeAddress, formatAmount, normalizeAddress, parseAmount, parseZkAddress, randomHex, shortenHex } from '@unlink-xyz/core';
5
+
6
+ /**
7
+ * Wallet note with value as bigint for convenience.
8
+ */
9
+ type WalletNote = Omit<NoteRecord, "value"> & {
10
+ value: bigint;
11
+ };
12
+ /** Shared fields for all pending job types. */
13
+ type PendingJobBase = {
14
+ txId: string;
15
+ status: HistoryStatus;
16
+ chainId: number;
17
+ token: string;
18
+ amount: bigint;
19
+ startedAt: number;
20
+ txHash?: string;
21
+ confirmedAt?: number;
22
+ };
23
+ type PendingDepositJob = PendingJobBase & {
24
+ commitment?: string;
25
+ };
26
+ type PendingTransferJob = PendingJobBase & {
27
+ recipient: string;
28
+ };
29
+ type PendingWithdrawJob = PendingJobBase & {
30
+ recipient: string;
31
+ };
32
+ /**
33
+ * Base configuration shared by all UnlinkProvider variants.
34
+ */
35
+ type UnlinkConfigBase = {
36
+ /** Chain ID for the target blockchain */
37
+ chainId: number;
38
+ /** Auto-sync interval in milliseconds (default: 5000) */
39
+ syncInterval?: number;
40
+ /** Whether to start auto-sync on mount (default: true) */
41
+ autoSync?: boolean;
42
+ /** Optional prover/artifact source override */
43
+ prover?: BrowserWalletOptions["prover"];
44
+ };
45
+ /**
46
+ * Configuration for the UnlinkProvider.
47
+ * Either provide explicit gatewayUrl + poolAddress, or environment to auto-resolve.
48
+ */
49
+ type UnlinkConfig = UnlinkConfigBase & ({
50
+ /** Explicit gateway URL - requires poolAddress */
51
+ gatewayUrl: string;
52
+ poolAddress: string;
53
+ environment?: never;
54
+ } | {
55
+ /** Environment to use from the config file */
56
+ environment: Environment;
57
+ /** Pool contract address - optional, defaults to environment config */
58
+ poolAddress?: string;
59
+ gatewayUrl?: never;
60
+ });
61
+ /**
62
+ * State exposed by the useUnlink hook.
63
+ */
64
+ type UnlinkState = {
65
+ /** The underlying wallet instance */
66
+ wallet: UnlinkWallet | null;
67
+ /** Whether a wallet (mnemonic) exists */
68
+ walletExists: boolean;
69
+ /** All derived accounts */
70
+ accounts: AccountInfo[];
71
+ /** Current active account (null if not created yet) */
72
+ activeAccount: Account | null;
73
+ /** Current active account index (null if none) */
74
+ activeAccountIndex: number | null;
75
+ /** Chain ID configured for this provider */
76
+ chainId: number;
77
+ /** User's notes with value as bigint */
78
+ notes: WalletNote[];
79
+ /** Token balances by address */
80
+ balances: Record<string, bigint>;
81
+ /** Pending deposit jobs */
82
+ pendingDeposits: PendingDepositJob[];
83
+ /** Pending transfer jobs */
84
+ pendingTransfers: PendingTransferJob[];
85
+ /** Pending withdraw jobs */
86
+ pendingWithdrawals: PendingWithdrawJob[];
87
+ /** Whether the SDK is initialized and ready */
88
+ ready: boolean;
89
+ /** Whether an operation is in progress */
90
+ busy: boolean;
91
+ /** Current status message */
92
+ status: string;
93
+ /** Last sync error message, or null if sync is healthy */
94
+ syncError: string | null;
95
+ /** Current error state (null if no error) */
96
+ error: UnlinkError | null;
97
+ };
98
+ /**
99
+ * Transfer parameters for useUnlink.send()
100
+ */
101
+ type TransferInput = {
102
+ token: string;
103
+ /** Unlink address (0zk1... bech32m) */
104
+ recipient: string;
105
+ amount: bigint;
106
+ };
107
+ /**
108
+ * Deposit parameters for useUnlink.deposit()
109
+ */
110
+ type DepositInput = {
111
+ token: string;
112
+ amount: bigint;
113
+ /** On-chain depositor address */
114
+ depositor: string;
115
+ };
116
+ /**
117
+ * Withdraw parameters for useUnlink.requestWithdraw()
118
+ */
119
+ type WithdrawInput = WithdrawalInput;
120
+ /**
121
+ * Actions exposed by the useUnlink hook.
122
+ */
123
+ type UnlinkActions = {
124
+ /** Create a new wallet. Returns mnemonic for backup. */
125
+ createWallet(): Promise<{
126
+ mnemonic: string;
127
+ }>;
128
+ /** Import an existing mnemonic */
129
+ importWallet(mnemonic: string): Promise<void>;
130
+ /** Export the stored mnemonic for backup */
131
+ exportMnemonic(): Promise<string>;
132
+ /** Clear all wallet data (destructive) */
133
+ clearWallet(): Promise<void>;
134
+ /** Create a new account at the specified or next available index */
135
+ createAccount(index?: number): Promise<Account>;
136
+ /** Switch to a different account by index */
137
+ switchAccount(index: number): Promise<void>;
138
+ /**
139
+ * High-level send (1 or more transfers).
140
+ * Multiple transfers are processed atomically.
141
+ *
142
+ * @param params - Array of transfers (token + amount + recipient)
143
+ * @returns TransferResult with array of plans
144
+ */
145
+ send(params: TransferInput[]): Promise<TransferResult>;
146
+ /**
147
+ * Get a transfer plan without executing (for preview).
148
+ * Validates balances and returns plans for each transfer.
149
+ *
150
+ * @param params - Array of transfers (token + amount + recipient)
151
+ * @returns Array of TransactionPlan
152
+ */
153
+ planTransfer(params: TransferInput[]): Promise<TransferPlanResult>;
154
+ /** Execute a pre-built transfer plan */
155
+ executeTransfer(plans: TransferPlanResult): Promise<TransferResult>;
156
+ /**
157
+ * Request a deposit (1 or more tokens).
158
+ * Returns calldata that the user must submit on-chain via their EOA.
159
+ * Use the returned `to` and `calldata` fields to construct the transaction.
160
+ *
161
+ * @param params - Array of deposits (token + amount + depositor)
162
+ * @returns DepositRelayResult with array of commitments
163
+ */
164
+ requestDeposit(params: DepositInput[]): Promise<DepositRelayResult>;
165
+ /**
166
+ * High-level withdraw (1 or more tokens).
167
+ * Specify recipient EOA + amount for each withdrawal.
168
+ * Multiple withdrawals are processed atomically.
169
+ *
170
+ * @param params - Array of withdrawals (token + amount + recipient)
171
+ * @returns WithdrawResult with array of plans
172
+ */
173
+ requestWithdraw(params: WithdrawInput[]): Promise<WithdrawResult>;
174
+ /**
175
+ * Get a withdrawal plan without executing (for preview).
176
+ * Validates balances and returns plans for each withdrawal.
177
+ *
178
+ * @param params - Array of withdrawals (token + amount + recipient)
179
+ * @returns Array of WithdrawalPlan
180
+ */
181
+ planWithdraw(params: WithdrawInput[]): Promise<WithdrawPlanResult>;
182
+ /** Execute a pre-built withdrawal plan */
183
+ executeWithdraw(plans: WithdrawPlanResult): Promise<WithdrawResult>;
184
+ /** Refresh notes and balances */
185
+ refresh(): Promise<void>;
186
+ /** Force full resync from chain */
187
+ forceResync(): Promise<void>;
188
+ /** Clear the current error state */
189
+ clearError(): void;
190
+ /**
191
+ * Get the current status of a transaction.
192
+ *
193
+ * @param txId - The transaction ID returned from deposit, transfer, or withdraw operations
194
+ * @returns The current status of the transaction
195
+ */
196
+ getTxStatus(txId: string): Promise<TxStatus>;
197
+ /**
198
+ * Wait for a transaction to reach a terminal state.
199
+ * Resolves when state is 'succeeded', throws on 'reverted'/'failed'/'dead' or timeout.
200
+ *
201
+ * @param txId - The transaction ID returned from deposit, transfer, or withdraw operations
202
+ * @param options - Optional configuration (timeout)
203
+ * @returns The final transaction status on success
204
+ * @throws TimeoutError if timeout exceeded
205
+ * @throws TransactionFailedError if transaction fails
206
+ */
207
+ waitForConfirmation(txId: string, options?: WaitForConfirmationOptions): Promise<TxStatus>;
208
+ };
209
+ /**
210
+ * Complete value returned by useUnlink hook.
211
+ */
212
+ type UnlinkContextValue = UnlinkState & UnlinkActions;
213
+ type TxState = RelayState;
214
+ /** Terminal states that indicate a transaction has finished processing */
215
+ declare const TERMINAL_TX_STATES: readonly TxState[];
216
+ /** Default timeout for waitForConfirmation (5 minutes) */
217
+ declare const DEFAULT_CONFIRMATION_TIMEOUT_MS: number;
218
+ /** Poll interval for waitForConfirmation (2 seconds) */
219
+ declare const CONFIRMATION_POLL_INTERVAL_MS = 2000;
220
+ /**
221
+ * Status information for a transaction.
222
+ */
223
+ type TxStatus = {
224
+ txId: string;
225
+ state: TxState;
226
+ txHash?: string;
227
+ blockNumber?: number;
228
+ error?: string;
229
+ };
230
+ /**
231
+ * Result from the useTxStatus hook.
232
+ */
233
+ type UseTxStatusResult = {
234
+ state: TxState | null;
235
+ txHash: string | null;
236
+ blockNumber: number | null;
237
+ error: string | null;
238
+ isLoading: boolean;
239
+ refresh: () => Promise<void>;
240
+ };
241
+ /**
242
+ * Options for waitForConfirmation.
243
+ */
244
+ type WaitForConfirmationOptions = {
245
+ /** Timeout in milliseconds (default: 300000 = 5 minutes) */
246
+ timeout?: number;
247
+ };
248
+ /**
249
+ * Error thrown when a transaction times out.
250
+ */
251
+ declare class TimeoutError extends Error {
252
+ readonly txId: string;
253
+ readonly timeout: number;
254
+ constructor(txId: string, timeout: number);
255
+ }
256
+ /**
257
+ * Error thrown when a transaction fails.
258
+ */
259
+ declare class TransactionFailedError extends Error {
260
+ readonly txId: string;
261
+ readonly state: TxState;
262
+ readonly reason?: string;
263
+ constructor(txId: string, state: TxState, reason?: string);
264
+ }
265
+ /**
266
+ * Error codes for categorizing errors in the Unlink context.
267
+ */
268
+ type UnlinkErrorCode = "UNKNOWN" | "SDK_NOT_INITIALIZED" | "NETWORK_ERROR" | "VALIDATION_ERROR" | "PROOF_ERROR" | "TIMEOUT" | "TRANSACTION_FAILED";
269
+ /**
270
+ * Operations that can trigger an error in the Unlink context.
271
+ */
272
+ type UnlinkErrorOperation = "init" | "createWallet" | "importWallet" | "clearWallet" | "createAccount" | "switchAccount" | "send" | "executeTransfer" | "requestDeposit" | "requestWithdraw" | "executeWithdraw" | "refresh" | "forceResync";
273
+ /**
274
+ * Structured error type for the Unlink context.
275
+ */
276
+ type UnlinkError = {
277
+ code: UnlinkErrorCode;
278
+ message: string;
279
+ operation: UnlinkErrorOperation;
280
+ timestamp: number;
281
+ details?: unknown;
282
+ };
283
+
284
+ type UnlinkProviderProps = UnlinkConfig & {
285
+ children: ReactNode;
286
+ };
287
+ declare function UnlinkProvider({ children, chainId, poolAddress, syncInterval, autoSync, gatewayUrl, environment, prover, }: UnlinkProviderProps): react_jsx_runtime.JSX.Element;
288
+
289
+ /**
290
+ * Hook to access the Unlink wallet SDK.
291
+ *
292
+ * Must be used within an UnlinkProvider.
293
+ *
294
+ * @example
295
+ * ```tsx
296
+ * function SendButton() {
297
+ * const { send, balances, ready, busy } = useUnlink();
298
+ *
299
+ * const handleSend = async () => {
300
+ * await send({
301
+ * token: "0x...",
302
+ * recipient: "0x...",
303
+ * amount: 100n,
304
+ * });
305
+ * };
306
+ *
307
+ * return (
308
+ * <button onClick={handleSend} disabled={!ready || busy}>
309
+ * Send
310
+ * </button>
311
+ * );
312
+ * }
313
+ * ```
314
+ */
315
+ declare function useUnlink(): UnlinkContextValue;
316
+
317
+ type UseUnlinkHistoryOptions = {
318
+ /** Include self-sends in history (transfers to own address) */
319
+ includeSelfSends?: boolean;
320
+ };
321
+ type UseUnlinkHistoryResult = {
322
+ history: HistoryEntry[];
323
+ loading: boolean;
324
+ error: Error | null;
325
+ refresh: () => Promise<void>;
326
+ };
327
+ /**
328
+ * Hook to get transaction history for the wallet.
329
+ *
330
+ * Uses the SDK's history service which provides properly categorized
331
+ * transaction entries (Deposit, Receive, Send, SelfSend, Withdraw).
332
+ *
333
+ * @example
334
+ * ```tsx
335
+ * function History() {
336
+ * const { history, loading } = useUnlinkHistory();
337
+ *
338
+ * if (loading) return <div>Loading...</div>;
339
+ *
340
+ * return (
341
+ * <ul>
342
+ * {history.map((entry) => (
343
+ * <li key={entry.id}>
344
+ * {entry.kind}: {entry.amounts[0]?.delta}
345
+ * </li>
346
+ * ))}
347
+ * </ul>
348
+ * );
349
+ * }
350
+ * ```
351
+ */
352
+ declare function useUnlinkHistory(options?: UseUnlinkHistoryOptions): UseUnlinkHistoryResult;
353
+
354
+ type UseUnlinkBalanceResult = {
355
+ /** Balance for the token (0n if not found) */
356
+ balance: bigint;
357
+ /** Whether the SDK is ready */
358
+ ready: boolean;
359
+ /** Whether data is loading */
360
+ loading: boolean;
361
+ };
362
+ /**
363
+ * Hook to get the balance for a specific token.
364
+ *
365
+ * @param token - Token address to get balance for
366
+ *
367
+ * @example
368
+ * ```tsx
369
+ * function TokenBalance({ token }: { token: string }) {
370
+ * const { balance, ready } = useUnlinkBalance(token);
371
+ *
372
+ * if (!ready) return <div>Loading...</div>;
373
+ *
374
+ * return <div>Balance: {balance.toString()}</div>;
375
+ * }
376
+ * ```
377
+ */
378
+ declare function useUnlinkBalance(token: string): UseUnlinkBalanceResult;
379
+ /**
380
+ * Hook to get all token balances.
381
+ *
382
+ * @example
383
+ * ```tsx
384
+ * function AllBalances() {
385
+ * const { balances, ready } = useUnlinkBalances();
386
+ *
387
+ * if (!ready) return <div>Loading...</div>;
388
+ *
389
+ * return (
390
+ * <ul>
391
+ * {Object.entries(balances).map(([token, balance]) => (
392
+ * <li key={token}>
393
+ * {token}: {balance.toString()}
394
+ * </li>
395
+ * ))}
396
+ * </ul>
397
+ * );
398
+ * }
399
+ * ```
400
+ */
401
+ declare function useUnlinkBalances(): {
402
+ balances: Record<string, bigint>;
403
+ ready: boolean;
404
+ loading: boolean;
405
+ };
406
+
407
+ /**
408
+ * Hook to track the status of a transaction.
409
+ *
410
+ * Subscribes to 'tx-status-changed' events from the wallet for real-time updates.
411
+ * The SDK automatically polls the broadcaster for tracked transactions.
412
+ * Once the transaction reaches a terminal state (succeeded, reverted, failed, dead),
413
+ * tracking automatically stops to avoid unnecessary API calls.
414
+ *
415
+ * Also provides a `refresh()` method for manual updates.
416
+ *
417
+ * @param txId - The transaction ID to track, or null to disable tracking
418
+ * @returns The current transaction status with loading state and refresh method
419
+ *
420
+ * @remarks
421
+ * **Error handling:** On fetch error, `state` retains its previous value while
422
+ * `error` is set. Always check `error` first when rendering status.
423
+ *
424
+ * @example
425
+ * ```tsx
426
+ * function TransactionStatus({ txId }: { txId: string }) {
427
+ * const { state, txHash, isLoading, error } = useTxStatus(txId);
428
+ *
429
+ * if (isLoading) return <span>Loading...</span>;
430
+ * if (error) return <span>Error: {error}</span>;
431
+ * if (state === 'succeeded') return <span>Confirmed! TX: {txHash}</span>;
432
+ *
433
+ * return <span>Status: {state}</span>;
434
+ * }
435
+ * ```
436
+ */
437
+ declare function useTxStatus(txId: string | null): UseTxStatusResult;
438
+
439
+ type UseOperationMutationResult<TInput, TOutput> = {
440
+ /** Execute the mutation */
441
+ mutate: (input: TInput) => Promise<TOutput>;
442
+ /** Last successful result */
443
+ data: TOutput | null;
444
+ /** Whether the mutation is currently running */
445
+ isPending: boolean;
446
+ /** Whether the last mutation succeeded */
447
+ isSuccess: boolean;
448
+ /** Whether the last mutation failed */
449
+ isError: boolean;
450
+ /** Error from the last failed mutation */
451
+ error: Error | null;
452
+ /** Reset state back to idle */
453
+ reset: () => void;
454
+ };
455
+ /**
456
+ * Generic async mutation state machine for wallet operations.
457
+ *
458
+ * Tracks loading, success, error, and data states.
459
+ * Prevents concurrent mutations (throws while a mutation is pending).
460
+ *
461
+ * @example
462
+ * ```tsx
463
+ * function DepositButton() {
464
+ * const { requestDeposit } = useUnlink();
465
+ * const { mutate, isPending, error } = useOperationMutation(requestDeposit);
466
+ *
467
+ * return (
468
+ * <button onClick={() => mutate(params)} disabled={isPending}>
469
+ * {isPending ? "Depositing..." : "Deposit"}
470
+ * </button>
471
+ * );
472
+ * }
473
+ * ```
474
+ */
475
+ declare function useOperationMutation<TInput, TOutput>(operation: (input: TInput) => Promise<TOutput>): UseOperationMutationResult<TInput, TOutput>;
476
+
477
+ /**
478
+ * Hook for requesting deposits with loading/error state.
479
+ *
480
+ * @example
481
+ * ```tsx
482
+ * function DepositForm() {
483
+ * const { mutate: deposit, isPending, error } = useDeposit();
484
+ *
485
+ * const handleDeposit = async () => {
486
+ * const result = await deposit([
487
+ * { token: "0x...", amount: 1000n, depositor: "0x..." },
488
+ * ]);
489
+ * // result.calldata — submit this on-chain
490
+ * };
491
+ *
492
+ * return (
493
+ * <button onClick={handleDeposit} disabled={isPending}>
494
+ * {isPending ? "Preparing..." : "Deposit"}
495
+ * </button>
496
+ * );
497
+ * }
498
+ * ```
499
+ */
500
+ declare function useDeposit(): UseOperationMutationResult<DepositInput[], DepositRelayResult>;
501
+
502
+ /**
503
+ * Hook for sending private transfers with loading/error state.
504
+ *
505
+ * @example
506
+ * ```tsx
507
+ * function SendForm() {
508
+ * const { mutate: send, isPending, error } = useTransfer();
509
+ *
510
+ * const handleSend = async () => {
511
+ * const result = await send([
512
+ * { token: "0x...", recipient: "0zk1...", amount: 100n },
513
+ * ]);
514
+ * console.log("Relay ID:", result.relayId);
515
+ * };
516
+ *
517
+ * return (
518
+ * <button onClick={handleSend} disabled={isPending}>
519
+ * {isPending ? "Sending..." : "Send"}
520
+ * </button>
521
+ * );
522
+ * }
523
+ * ```
524
+ */
525
+ declare function useTransfer(): UseOperationMutationResult<TransferInput[], TransferResult>;
526
+
527
+ /**
528
+ * Hook for requesting withdrawals with loading/error state.
529
+ *
530
+ * @example
531
+ * ```tsx
532
+ * function WithdrawForm() {
533
+ * const { mutate: withdraw, isPending, error } = useWithdraw();
534
+ *
535
+ * const handleWithdraw = async () => {
536
+ * const result = await withdraw([
537
+ * { token: "0x...", amount: 50n, recipient: "0x..." },
538
+ * ]);
539
+ * console.log("Relay ID:", result.relayId);
540
+ * };
541
+ *
542
+ * return (
543
+ * <button onClick={handleWithdraw} disabled={isPending}>
544
+ * {isPending ? "Withdrawing..." : "Withdraw"}
545
+ * </button>
546
+ * );
547
+ * }
548
+ * ```
549
+ */
550
+ declare function useWithdraw(): UseOperationMutationResult<WithdrawInput[], WithdrawResult>;
551
+
552
+ export { CONFIRMATION_POLL_INTERVAL_MS, DEFAULT_CONFIRMATION_TIMEOUT_MS, type DepositInput, type PendingDepositJob, type PendingTransferJob, type PendingWithdrawJob, TERMINAL_TX_STATES, TimeoutError, TransactionFailedError, type TransferInput, type TxState, type TxStatus, type UnlinkActions, type UnlinkConfig, type UnlinkContextValue, type UnlinkError, type UnlinkErrorCode, type UnlinkErrorOperation, UnlinkProvider, type UnlinkProviderProps, type UnlinkState, type UseOperationMutationResult, type UseTxStatusResult, type UseUnlinkBalanceResult, type UseUnlinkHistoryOptions, type UseUnlinkHistoryResult, type WaitForConfirmationOptions, type WalletNote, type WithdrawInput, useDeposit, useOperationMutation, useTransfer, useTxStatus, useUnlink, useUnlinkBalance, useUnlinkBalances, useUnlinkHistory, useWithdraw };