@etherkit/viem-tx-tracker 0.0.4 → 0.0.5

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/src/types.ts CHANGED
@@ -15,6 +15,53 @@ import type {
15
15
  WriteContractParameters,
16
16
  } from 'viem';
17
17
 
18
+ /**
19
+ * Metadata for contract function calls.
20
+ * Auto-populated by writeContract when populateMetadata: true.
21
+ */
22
+ export type FunctionCallMetadata = {
23
+ type: 'functionCall';
24
+ functionName: string;
25
+ args?: readonly unknown[];
26
+ };
27
+
28
+ /**
29
+ * Metadata for unknown/untyped operations.
30
+ * Used as a fallback for sendTransaction/sendRawTransaction
31
+ * when using the default PopulatedMetadata type.
32
+ */
33
+ export type UnknownTypeMetadata = {
34
+ type: 'unknown';
35
+ name: string;
36
+ data: any[];
37
+ };
38
+
39
+ /**
40
+ * Default metadata type when using populateMetadata: true.
41
+ * A discriminated union that allows either:
42
+ * - FunctionCallMetadata (auto-populated by writeContract)
43
+ * - UnknownTypeMetadata (for sendTransaction/sendRawTransaction)
44
+ *
45
+ * Users can provide their own TMetadata type that excludes 'unknown'
46
+ * if they want to enforce specific operation types.
47
+ */
48
+ export type PopulatedMetadata = FunctionCallMetadata | UnknownTypeMetadata;
49
+
50
+ /**
51
+ * Options for creating a tracked wallet client.
52
+ */
53
+ export interface CreateTrackedWalletClientOptions<
54
+ TPopulate extends boolean = false,
55
+ > {
56
+ /**
57
+ * When true, writeContract and writeContractSync automatically populate
58
+ * operation, functionName and args in the metadata from the contract call parameters.
59
+ * TMetadata must be a type where FunctionCallMetadata is assignable to it
60
+ * (e.g., PopulatedMetadata, FunctionCallMetadata, or a union including FunctionCallMetadata).
61
+ */
62
+ populateMetadata?: TPopulate;
63
+ }
64
+
18
65
  /**
19
66
  * Block tags that can be used to specify nonce fetching strategy
20
67
  */
@@ -28,29 +75,6 @@ export type BlockTag = 'latest' | 'pending' | 'earliest' | 'safe' | 'finalized';
28
75
  */
29
76
  export type NonceOption = number | BlockTag;
30
77
 
31
- export type ExpectedUpdate =
32
- | {
33
- address: `0x${string}`;
34
- event: {topics: `0x${string}`[]};
35
- }
36
- | {
37
- address: `0x${string}`;
38
- call: {data: `0x${string}`; result: `0x${string}`};
39
- };
40
-
41
- /**
42
- * Metadata that can be attached to a transaction for tracking purposes.
43
- * All fields are optional and extensible.
44
- */
45
- export interface TransactionMetadata {
46
- id?: string;
47
- name?: string;
48
- args?: any[];
49
- description?: string;
50
- expectedUpdate?: ExpectedUpdate;
51
- [key: string]: unknown;
52
- }
53
-
54
78
  /**
55
79
  * Conditional type that makes metadata required or optional based on TMetadata.
56
80
  * If TMetadata includes undefined (e.g., `MyMeta | undefined`), metadata is optional.
@@ -110,6 +134,98 @@ export type TrackedWriteContractParameters<
110
134
  nonce?: NonceOption;
111
135
  } & MetadataField<TMetadata>;
112
136
 
137
+ /**
138
+ * The fields that are auto-populated by writeContract.
139
+ * These are excluded from user-provided metadata for writeContract.
140
+ */
141
+ export type AutoPopulatedFields = 'type' | 'functionName' | 'args';
142
+
143
+ /**
144
+ * Type that explicitly forbids auto-populated fields.
145
+ * Uses never to make TypeScript error when these properties are provided.
146
+ */
147
+ export type ForbiddenAutoPopulateFields = {
148
+ type?: never;
149
+ functionName?: never;
150
+ args?: never;
151
+ };
152
+
153
+ /**
154
+ * Metadata type for writeContract when auto-population is enabled.
155
+ * Excludes operation, functionName and args since they will be auto-populated,
156
+ * and explicitly forbids them to cause TypeScript errors if provided.
157
+ *
158
+ * User provides the remaining fields (e.g., purpose, priority), and the
159
+ * auto-populated fields (operation, functionName, args) are added at runtime.
160
+ */
161
+ export type WriteContractAutoPopulateMetadata<TMetadata> = Omit<
162
+ TMetadata,
163
+ AutoPopulatedFields
164
+ > &
165
+ ForbiddenAutoPopulateFields;
166
+
167
+ /**
168
+ * Metadata field for writeContract when auto-population is enabled.
169
+ * Excludes operation, functionName and args since they will be auto-populated.
170
+ *
171
+ * If the remaining fields (after removing auto-populated fields) are all optional,
172
+ * the metadata field itself becomes optional.
173
+ */
174
+ export type WriteContractAutoPopulateMetadataField<TMetadata> =
175
+ // Check if there are any remaining required keys after removing auto-populated fields
176
+ keyof Omit<TMetadata, AutoPopulatedFields> extends never
177
+ ? // No other fields - metadata is optional (can be omitted entirely)
178
+ {metadata?: WriteContractAutoPopulateMetadata<TMetadata>}
179
+ : // Check if all remaining fields are optional
180
+ Partial<Omit<TMetadata, AutoPopulatedFields>> extends Omit<
181
+ TMetadata,
182
+ AutoPopulatedFields
183
+ >
184
+ ? // All remaining fields are optional - metadata field is optional
185
+ {metadata?: WriteContractAutoPopulateMetadata<TMetadata>}
186
+ : // Some fields are required - metadata field is required
187
+ {metadata: WriteContractAutoPopulateMetadata<TMetadata>};
188
+
189
+ /**
190
+ * Extended WriteContractParameters with auto-populated metadata.
191
+ * operation, functionName and args are excluded from the metadata since they're auto-populated.
192
+ *
193
+ * User provides any additional fields required by their TMetadata (e.g., purpose, priority),
194
+ * and the auto-populated fields are merged at runtime.
195
+ */
196
+ export type TrackedWriteContractAutoPopulateParameters<
197
+ TMetadata,
198
+ TAbi extends Abi | readonly unknown[] = Abi,
199
+ TFunctionName extends ContractFunctionName<TAbi, 'nonpayable' | 'payable'> =
200
+ ContractFunctionName<TAbi, 'nonpayable' | 'payable'>,
201
+ TArgs extends ContractFunctionArgs<
202
+ TAbi,
203
+ 'nonpayable' | 'payable',
204
+ TFunctionName
205
+ > = ContractFunctionArgs<TAbi, 'nonpayable' | 'payable', TFunctionName>,
206
+ TChain extends Chain | undefined = Chain | undefined,
207
+ TAccount extends Account | undefined = Account | undefined,
208
+ TChainOverride extends Chain | undefined = Chain | undefined,
209
+ > = Omit<
210
+ WriteContractParameters<
211
+ TAbi,
212
+ TFunctionName,
213
+ TArgs,
214
+ TChain,
215
+ TAccount,
216
+ TChainOverride
217
+ >,
218
+ 'nonce'
219
+ > & {
220
+ /**
221
+ * Nonce option:
222
+ * - number: exact nonce to use
223
+ * - BlockTag ('latest', 'pending', etc.): fetch nonce using this block tag
224
+ * - undefined: fetch nonce using 'pending' (default)
225
+ */
226
+ nonce?: NonceOption;
227
+ } & WriteContractAutoPopulateMetadataField<TMetadata>;
228
+
113
229
  /**
114
230
  * Extended SendTransactionParameters with metadata and flexible nonce.
115
231
  * Metadata is required unless TMetadata includes undefined.
@@ -288,3 +404,150 @@ export interface TrackedWalletClient<
288
404
  listener: (event: TrackedTransaction<TMetadata>) => void,
289
405
  ): void;
290
406
  }
407
+
408
+ /**
409
+ * A wallet client wrapper that tracks transactions with auto-populated metadata.
410
+ * TMetadata must be a type where FunctionCallMetadata is assignable to it.
411
+ * writeContract and writeContractSync automatically populate operation, functionName and args.
412
+ */
413
+ export interface TrackedWalletClientAutoPopulate<
414
+ TMetadata,
415
+ TTransport extends Transport = Transport,
416
+ TChain extends Chain | undefined = Chain | undefined,
417
+ TAccount extends Account | undefined = Account | undefined,
418
+ > {
419
+ /**
420
+ * The underlying wallet client.
421
+ */
422
+ readonly walletClient: WalletClient<TTransport, TChain, TAccount>;
423
+
424
+ /**
425
+ * The public client used for nonce fetching and tx verification.
426
+ */
427
+ readonly publicClient: PublicClient;
428
+
429
+ // ============================================
430
+ // Async methods (return hash immediately after broadcast)
431
+ // ============================================
432
+
433
+ /**
434
+ * Write to a contract with metadata tracking.
435
+ * functionName and args are automatically populated from the contract call.
436
+ * Returns immediately after broadcast with the transaction hash.
437
+ */
438
+ writeContract<
439
+ const TAbi extends Abi | readonly unknown[],
440
+ TFunctionName extends ContractFunctionName<TAbi, 'nonpayable' | 'payable'>,
441
+ TArgs extends ContractFunctionArgs<
442
+ TAbi,
443
+ 'nonpayable' | 'payable',
444
+ TFunctionName
445
+ >,
446
+ TChainOverride extends Chain | undefined = undefined,
447
+ >(
448
+ args: TrackedWriteContractAutoPopulateParameters<
449
+ TMetadata,
450
+ TAbi,
451
+ TFunctionName,
452
+ TArgs,
453
+ TChain,
454
+ TAccount,
455
+ TChainOverride
456
+ >,
457
+ ): Promise<Hash>;
458
+
459
+ /**
460
+ * Send a transaction with metadata tracking.
461
+ * Returns immediately after broadcast with the transaction hash.
462
+ */
463
+ sendTransaction<TChainOverride extends Chain | undefined = undefined>(
464
+ args: TrackedSendTransactionParameters<
465
+ TMetadata,
466
+ TChain,
467
+ TAccount,
468
+ TChainOverride
469
+ >,
470
+ ): Promise<Hash>;
471
+
472
+ /**
473
+ * Send a signed raw transaction with metadata tracking.
474
+ * The nonce and from address are decoded from the serialized transaction.
475
+ * Returns immediately after broadcast with the transaction hash.
476
+ */
477
+ sendRawTransaction(
478
+ args: TrackedRawTransactionParameters<TMetadata>,
479
+ ): Promise<Hash>;
480
+
481
+ // ============================================
482
+ // Sync methods (wait for confirmation, return receipt)
483
+ // ============================================
484
+
485
+ /**
486
+ * Write to a contract and wait for confirmation.
487
+ * functionName and args are automatically populated from the contract call.
488
+ * Returns the transaction receipt after the transaction is confirmed.
489
+ */
490
+ writeContractSync<
491
+ const TAbi extends Abi | readonly unknown[],
492
+ TFunctionName extends ContractFunctionName<TAbi, 'nonpayable' | 'payable'>,
493
+ TArgs extends ContractFunctionArgs<
494
+ TAbi,
495
+ 'nonpayable' | 'payable',
496
+ TFunctionName
497
+ >,
498
+ TChainOverride extends Chain | undefined = undefined,
499
+ >(
500
+ args: TrackedWriteContractAutoPopulateParameters<
501
+ TMetadata,
502
+ TAbi,
503
+ TFunctionName,
504
+ TArgs,
505
+ TChain,
506
+ TAccount,
507
+ TChainOverride
508
+ >,
509
+ ): Promise<TransactionReceipt>;
510
+
511
+ /**
512
+ * Send a transaction and wait for confirmation.
513
+ * Returns the transaction receipt after the transaction is confirmed.
514
+ */
515
+ sendTransactionSync<TChainOverride extends Chain | undefined = undefined>(
516
+ args: TrackedSendTransactionParameters<
517
+ TMetadata,
518
+ TChain,
519
+ TAccount,
520
+ TChainOverride
521
+ >,
522
+ ): Promise<TransactionReceipt>;
523
+
524
+ /**
525
+ * Send a signed raw transaction and wait for confirmation.
526
+ * Returns the transaction receipt after the transaction is confirmed.
527
+ */
528
+ sendRawTransactionSync(
529
+ args: TrackedRawTransactionParameters<TMetadata>,
530
+ ): Promise<TransactionReceipt>;
531
+
532
+ // ============================================
533
+ // Event subscription methods
534
+ // ============================================
535
+
536
+ /**
537
+ * Subscribe to transaction broadcast events.
538
+ * Called immediately after a transaction is successfully broadcast.
539
+ * @param listener - Callback function receiving TrackedTransaction with TMetadata
540
+ * @returns Unsubscribe function
541
+ */
542
+ onTransactionBroadcasted(
543
+ listener: (event: TrackedTransaction<TMetadata>) => void,
544
+ ): () => void;
545
+
546
+ /**
547
+ * Unsubscribe from transaction broadcast events.
548
+ * @param listener - The same listener function passed to onTransactionBroadcasted
549
+ */
550
+ offTransactionBroadcasted(
551
+ listener: (event: TrackedTransaction<TMetadata>) => void,
552
+ ): void;
553
+ }