@etherkit/viem-tx-tracker 0.0.3 → 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.
@@ -29,234 +29,462 @@ function normalizeAccount(account) {
29
29
  function generateTrackingId() {
30
30
  return crypto.randomUUID();
31
31
  }
32
- /**
33
- * Create a tracked wallet client that wraps a viem WalletClient.
34
- *
35
- * The tracked client provides the same API as WalletClient but with:
36
- * - Optional metadata field for transaction tracking
37
- * - Automatic nonce fetching (with 'pending' by default)
38
- * - Post-broadcast transaction verification
39
- * - TODO: Event emission for tracking
40
- *
41
- * @param walletClient - The underlying viem WalletClient
42
- * @param publicClient - A PublicClient for nonce fetching and tx verification
43
- * @returns A TrackedWalletClient instance
44
- */
45
- export function createTrackedWalletClient(walletClient, publicClient) {
46
- // Create emitter for transaction broadcast events
47
- const emitter = new Emitter();
48
- /**
49
- * Resolve the nonce to use for a transaction.
50
- *
51
- * @param nonceOption - The nonce option provided by the caller
52
- * @param from - The sender address
53
- * @returns The resolved nonce number
54
- */
55
- async function resolveNonce(nonceOption, from) {
56
- if (typeof nonceOption === 'number') {
57
- // Explicit number - use as-is
58
- return nonceOption;
59
- }
60
- // Block tag (string) or undefined - fetch from chain
61
- const blockTag = isBlockTag(nonceOption) ? nonceOption : 'pending';
62
- return await publicClient.getTransactionCount({
63
- address: from,
64
- blockTag,
65
- });
66
- }
67
- /**
68
- * Extract common transaction context (account, nonce) from request args.
69
- * This is the shared logic between all transaction methods.
70
- *
71
- * @param args - The transaction args containing account and nonce options
72
- * @returns TransactionContext with resolved from address and nonce
73
- */
74
- async function extractTransactionContext(args) {
75
- // Get account/from address
76
- const account = args.account ?? walletClient.account;
77
- const from = resolveAccountAddress(account);
78
- if (!from) {
79
- throw new Error('[TrackedWalletClient] No account available. ' +
80
- 'Provide an account in the request or configure the wallet client with an account.');
81
- }
82
- // Resolve nonce
83
- const intendedNonce = await resolveNonce(args.nonce, from);
84
- return { from, intendedNonce };
85
- }
86
- /**
87
- * Extract transaction context from a serialized (signed) transaction.
88
- * Parses the transaction and recovers the sender address.
89
- *
90
- * @param serializedTransaction - The RLP-encoded signed transaction
91
- * @returns TransactionContext with from address and nonce
92
- */
93
- async function extractRawTransactionContext(serializedTransaction) {
94
- // Parse the serialized transaction to get the nonce
95
- const parsedTx = parseTransaction(serializedTransaction);
96
- if (parsedTx.nonce === undefined) {
97
- throw new Error('[TrackedWalletClient] Could not extract nonce from serialized transaction.');
98
- }
99
- // Recover the sender address from the signature
100
- const from = await recoverTransactionAddress({
101
- serializedTransaction,
102
- });
103
- return {
104
- from,
105
- intendedNonce: parsedTx.nonce,
106
- };
107
- }
108
- /**
109
- * Fetch the transaction after broadcast to verify nonce.
110
- * Logs a warning if the nonce was overridden or if tx cannot be found.
111
- *
112
- * @param hash - The transaction hash
113
- * @param intendedNonce - The nonce we intended to use
114
- * @returns The actual nonce, or the intended nonce if fetch failed
115
- */
116
- async function verifyTransactionNonce(hash, intendedNonce) {
117
- try {
118
- const tx = await publicClient.getTransaction({ hash });
119
- const actualNonce = tx.nonce;
120
- if (actualNonce !== intendedNonce) {
121
- console.warn(`[TrackedWalletClient] Nonce mismatch: intended ${intendedNonce}, actual ${actualNonce}. ` +
122
- `Wallet may have overridden the nonce.`);
123
- }
124
- return actualNonce;
125
- }
126
- catch (fetchError) {
127
- // Transaction not found in mempool/chain yet
128
- console.warn(`[TrackedWalletClient] Could not fetch tx ${hash} after broadcast. ` +
129
- `It may not be in the mempool yet.`);
130
- return intendedNonce;
131
- }
132
- }
133
- /**
134
- * Create a tracked transaction record.
135
- */
136
- function createTrackedTransaction(txHash, from, nonce, metadata, request) {
137
- return {
138
- hash: txHash,
139
- from,
140
- nonce,
141
- chainId: walletClient.chain?.id,
142
- metadata: (metadata ?? {}),
143
- broadcastTimestampMs: Date.now(),
144
- };
145
- }
146
- /**
147
- * Common wrapper for transaction methods that broadcast (sendTransaction, writeContract).
148
- * Handles nonce resolution, underlying call, post-broadcast verification, and tracking record creation.
149
- */
150
- async function executeTrackedTransaction(args) {
151
- const { metadata, restArgs, execute, extractHash } = args;
152
- // Extract common context
153
- const { from, intendedNonce } = await extractTransactionContext(args);
154
- // Execute the underlying transaction with nonce injected
155
- const result = await execute({ ...restArgs, nonce: intendedNonce });
156
- const hash = extractHash(result);
157
- // Verify transaction and get actual nonce
158
- const actualNonce = await verifyTransactionNonce(hash, intendedNonce);
159
- // Create tracked transaction record
160
- const trackedTx = createTrackedTransaction(hash, from, actualNonce, metadata, restArgs);
161
- // Emit transaction broadcasted event
162
- emitter.emit('transaction:broadcasted', trackedTx);
163
- return result;
164
- }
165
- /**
166
- * Common wrapper for raw transaction broadcasts (sendRawTransaction).
167
- * Decodes the transaction to extract from/nonce, broadcasts, and creates tracking record.
168
- */
169
- async function executeTrackedRawTransaction(args) {
170
- const { serializedTransaction, metadata, execute, extractHash } = args;
171
- // Extract context from the serialized transaction
172
- const { from, intendedNonce } = await extractRawTransactionContext(serializedTransaction);
173
- // Execute the broadcast
174
- const result = await execute();
175
- const hash = extractHash(result);
176
- // For raw transactions, the nonce is already embedded, so no verification needed
177
- // (wallet cannot override nonce in an already-signed transaction)
178
- // Create tracked transaction record
179
- const trackedTx = createTrackedTransaction(hash, from, intendedNonce, metadata, { serializedTransaction });
180
- // Emit transaction broadcasted event
181
- emitter.emit('transaction:broadcasted', trackedTx);
182
- return result;
32
+ // Implementation
33
+ export function createTrackedWalletClient(options) {
34
+ const populateMetadata = options?.populateMetadata ?? false;
35
+ if (populateMetadata) {
36
+ return createAutoPopulateBuilder();
183
37
  }
184
38
  return {
185
- walletClient,
186
- publicClient,
187
- // ============================================
188
- // Async methods (return hash)
189
- // ============================================
190
- async writeContract(args) {
191
- const { metadata, nonce, ...writeArgs } = args;
192
- return executeTrackedTransaction({
193
- account: normalizeAccount(args.account),
194
- nonce,
195
- metadata,
196
- restArgs: writeArgs,
197
- execute: (argsWithNonce) => walletClient.writeContract(argsWithNonce),
198
- extractHash: (hash) => hash,
199
- });
200
- },
201
- async sendTransaction(args) {
202
- const { metadata, nonce, ...sendArgs } = args;
203
- return executeTrackedTransaction({
204
- account: normalizeAccount(args.account),
205
- nonce,
206
- metadata,
207
- restArgs: sendArgs,
208
- execute: (argsWithNonce) => walletClient.sendTransaction(argsWithNonce),
209
- extractHash: (hash) => hash,
210
- });
211
- },
212
- async sendRawTransaction(args) {
213
- const { metadata, serializedTransaction } = args;
214
- return executeTrackedRawTransaction({
215
- serializedTransaction,
216
- metadata,
217
- execute: () => walletClient.sendRawTransaction({ serializedTransaction }),
218
- extractHash: (hash) => hash,
219
- });
220
- },
221
- // ============================================
222
- // Sync methods (return receipt, wait for confirmation)
223
- // ============================================
224
- async writeContractSync(args) {
225
- const { metadata, nonce, ...writeArgs } = args;
226
- return executeTrackedTransaction({
227
- account: normalizeAccount(args.account),
228
- nonce,
229
- metadata,
230
- restArgs: writeArgs,
231
- execute: (argsWithNonce) => walletClient.writeContractSync(argsWithNonce),
232
- extractHash: (receipt) => receipt.transactionHash,
233
- });
234
- },
235
- async sendTransactionSync(args) {
236
- const { metadata, nonce, ...sendArgs } = args;
237
- return executeTrackedTransaction({
238
- account: normalizeAccount(args.account),
239
- nonce,
240
- metadata,
241
- restArgs: sendArgs,
242
- execute: (argsWithNonce) => walletClient.sendTransactionSync(argsWithNonce),
243
- extractHash: (receipt) => receipt.transactionHash,
244
- });
39
+ using(walletClient, publicClient) {
40
+ // Create emitter for transaction broadcast events
41
+ const emitter = new Emitter();
42
+ /**
43
+ * Resolve the nonce to use for a transaction.
44
+ *
45
+ * @param nonceOption - The nonce option provided by the caller
46
+ * @param from - The sender address
47
+ * @returns The resolved nonce number
48
+ */
49
+ async function resolveNonce(nonceOption, from) {
50
+ if (typeof nonceOption === 'number') {
51
+ // Explicit number - use as-is
52
+ return nonceOption;
53
+ }
54
+ // Block tag (string) or undefined - fetch from chain
55
+ const blockTag = isBlockTag(nonceOption) ? nonceOption : 'pending';
56
+ return await publicClient.getTransactionCount({
57
+ address: from,
58
+ blockTag,
59
+ });
60
+ }
61
+ /**
62
+ * Extract common transaction context (account, nonce) from request args.
63
+ * This is the shared logic between all transaction methods.
64
+ *
65
+ * @param args - The transaction args containing account and nonce options
66
+ * @returns TransactionContext with resolved from address and nonce
67
+ */
68
+ async function extractTransactionContext(args) {
69
+ // Get account/from address
70
+ const account = args.account ?? walletClient.account;
71
+ const from = resolveAccountAddress(account);
72
+ if (!from) {
73
+ throw new Error('[TrackedWalletClient] No account available. ' +
74
+ 'Provide an account in the request or configure the wallet client with an account.');
75
+ }
76
+ // Resolve nonce
77
+ const intendedNonce = await resolveNonce(args.nonce, from);
78
+ return { from, intendedNonce };
79
+ }
80
+ /**
81
+ * Extract transaction context from a serialized (signed) transaction.
82
+ * Parses the transaction and recovers the sender address.
83
+ *
84
+ * @param serializedTransaction - The RLP-encoded signed transaction
85
+ * @returns TransactionContext with from address and nonce
86
+ */
87
+ async function extractRawTransactionContext(serializedTransaction) {
88
+ // Parse the serialized transaction to get the nonce
89
+ const parsedTx = parseTransaction(serializedTransaction);
90
+ if (parsedTx.nonce === undefined) {
91
+ throw new Error('[TrackedWalletClient] Could not extract nonce from serialized transaction.');
92
+ }
93
+ // Recover the sender address from the signature
94
+ const from = await recoverTransactionAddress({
95
+ serializedTransaction,
96
+ });
97
+ return {
98
+ from,
99
+ intendedNonce: parsedTx.nonce,
100
+ };
101
+ }
102
+ /**
103
+ * Fetch the transaction after broadcast to verify nonce.
104
+ * Logs a warning if the nonce was overridden or if tx cannot be found.
105
+ *
106
+ * @param hash - The transaction hash
107
+ * @param intendedNonce - The nonce we intended to use
108
+ * @returns The actual nonce, or the intended nonce if fetch failed
109
+ */
110
+ async function verifyTransactionNonce(hash, intendedNonce) {
111
+ try {
112
+ const tx = await publicClient.getTransaction({ hash });
113
+ const actualNonce = tx.nonce;
114
+ if (actualNonce !== intendedNonce) {
115
+ console.warn(`[TrackedWalletClient] Nonce mismatch: intended ${intendedNonce}, actual ${actualNonce}. ` +
116
+ `Wallet may have overridden the nonce.`);
117
+ }
118
+ return actualNonce;
119
+ }
120
+ catch (fetchError) {
121
+ // Transaction not found in mempool/chain yet
122
+ console.warn(`[TrackedWalletClient] Could not fetch tx ${hash} after broadcast. ` +
123
+ `It may not be in the mempool yet.`);
124
+ return intendedNonce;
125
+ }
126
+ }
127
+ /**
128
+ * Create a tracked transaction record.
129
+ */
130
+ function createTrackedTransactionRecord(txHash, from, nonce, metadata) {
131
+ return {
132
+ hash: txHash,
133
+ from,
134
+ nonce,
135
+ chainId: walletClient.chain?.id,
136
+ metadata,
137
+ broadcastTimestampMs: Date.now(),
138
+ };
139
+ }
140
+ /**
141
+ * Common wrapper for transaction methods that broadcast (sendTransaction, writeContract).
142
+ * Handles nonce resolution, underlying call, post-broadcast verification, and tracking record creation.
143
+ */
144
+ async function executeTrackedTransaction(args) {
145
+ const { metadata, restArgs, execute, extractHash } = args;
146
+ // Extract common context
147
+ const { from, intendedNonce } = await extractTransactionContext(args);
148
+ // Execute the underlying transaction with nonce injected
149
+ const result = await execute({
150
+ ...restArgs,
151
+ nonce: intendedNonce,
152
+ });
153
+ const hash = extractHash(result);
154
+ // Verify transaction and get actual nonce
155
+ const actualNonce = await verifyTransactionNonce(hash, intendedNonce);
156
+ // Create tracked transaction record
157
+ const trackedTx = createTrackedTransactionRecord(hash, from, actualNonce, metadata);
158
+ // Emit transaction broadcasted event
159
+ emitter.emit('transaction:broadcasted', trackedTx);
160
+ return result;
161
+ }
162
+ /**
163
+ * Common wrapper for raw transaction broadcasts (sendRawTransaction).
164
+ * Decodes the transaction to extract from/nonce, broadcasts, and creates tracking record.
165
+ */
166
+ async function executeTrackedRawTransaction(args) {
167
+ const { serializedTransaction, metadata, execute, extractHash } = args;
168
+ // Extract context from the serialized transaction
169
+ const { from, intendedNonce } = await extractRawTransactionContext(serializedTransaction);
170
+ // Execute the broadcast
171
+ const result = await execute();
172
+ const hash = extractHash(result);
173
+ // For raw transactions, the nonce is already embedded, so no verification needed
174
+ // (wallet cannot override nonce in an already-signed transaction)
175
+ // Create tracked transaction record
176
+ const trackedTx = createTrackedTransactionRecord(hash, from, intendedNonce, metadata);
177
+ // Emit transaction broadcasted event
178
+ emitter.emit('transaction:broadcasted', trackedTx);
179
+ return result;
180
+ }
181
+ return {
182
+ walletClient: walletClient,
183
+ publicClient,
184
+ // ============================================
185
+ // Async methods (return hash)
186
+ // ============================================
187
+ async writeContract(args) {
188
+ const { metadata, nonce, ...writeArgs } = args;
189
+ return executeTrackedTransaction({
190
+ account: normalizeAccount(args.account),
191
+ nonce,
192
+ metadata: metadata,
193
+ restArgs: writeArgs,
194
+ execute: (argsWithNonce) => walletClient.writeContract(argsWithNonce),
195
+ extractHash: (hash) => hash,
196
+ });
197
+ },
198
+ async sendTransaction(args) {
199
+ const { metadata, nonce, ...sendArgs } = args;
200
+ return executeTrackedTransaction({
201
+ account: normalizeAccount(args.account),
202
+ nonce,
203
+ metadata: metadata,
204
+ restArgs: sendArgs,
205
+ execute: (argsWithNonce) => walletClient.sendTransaction(argsWithNonce),
206
+ extractHash: (hash) => hash,
207
+ });
208
+ },
209
+ async sendRawTransaction(args) {
210
+ const { metadata, serializedTransaction } = args;
211
+ return executeTrackedRawTransaction({
212
+ serializedTransaction,
213
+ metadata: metadata,
214
+ execute: () => walletClient.sendRawTransaction({ serializedTransaction }),
215
+ extractHash: (hash) => hash,
216
+ });
217
+ },
218
+ // ============================================
219
+ // Sync methods (return receipt, wait for confirmation)
220
+ // ============================================
221
+ async writeContractSync(args) {
222
+ const { metadata, nonce, ...writeArgs } = args;
223
+ return executeTrackedTransaction({
224
+ account: normalizeAccount(args.account),
225
+ nonce,
226
+ metadata: metadata,
227
+ restArgs: writeArgs,
228
+ execute: (argsWithNonce) => walletClient.writeContractSync(argsWithNonce),
229
+ extractHash: (receipt) => receipt.transactionHash,
230
+ });
231
+ },
232
+ async sendTransactionSync(args) {
233
+ const { metadata, nonce, ...sendArgs } = args;
234
+ return executeTrackedTransaction({
235
+ account: normalizeAccount(args.account),
236
+ nonce,
237
+ metadata: metadata,
238
+ restArgs: sendArgs,
239
+ execute: (argsWithNonce) => walletClient.sendTransactionSync(argsWithNonce),
240
+ extractHash: (receipt) => receipt.transactionHash,
241
+ });
242
+ },
243
+ async sendRawTransactionSync(args) {
244
+ const { metadata, serializedTransaction } = args;
245
+ return executeTrackedRawTransaction({
246
+ serializedTransaction,
247
+ metadata: metadata,
248
+ execute: () => walletClient.sendRawTransactionSync({ serializedTransaction }),
249
+ extractHash: (receipt) => receipt.transactionHash,
250
+ });
251
+ },
252
+ // ============================================
253
+ // Event subscription methods
254
+ // ============================================
255
+ onTransactionBroadcasted: (listener) => emitter.on('transaction:broadcasted', listener),
256
+ offTransactionBroadcasted: (listener) => emitter.off('transaction:broadcasted', listener),
257
+ };
245
258
  },
246
- async sendRawTransactionSync(args) {
247
- const { metadata, serializedTransaction } = args;
248
- return executeTrackedRawTransaction({
249
- serializedTransaction,
250
- metadata,
251
- execute: () => walletClient.sendRawTransactionSync({ serializedTransaction }),
252
- extractHash: (receipt) => receipt.transactionHash,
253
- });
259
+ };
260
+ }
261
+ /**
262
+ * Create an auto-populate builder for TrackedWalletClient.
263
+ * This builder auto-populates operation, functionName and args in writeContract metadata.
264
+ */
265
+ function createAutoPopulateBuilder() {
266
+ return {
267
+ using(walletClient, publicClient) {
268
+ // Create emitter for transaction broadcast events
269
+ const emitter = new Emitter();
270
+ /**
271
+ * Resolve the nonce to use for a transaction.
272
+ */
273
+ async function resolveNonce(nonceOption, from) {
274
+ if (typeof nonceOption === 'number') {
275
+ return nonceOption;
276
+ }
277
+ const blockTag = isBlockTag(nonceOption) ? nonceOption : 'pending';
278
+ return await publicClient.getTransactionCount({
279
+ address: from,
280
+ blockTag,
281
+ });
282
+ }
283
+ /**
284
+ * Extract common transaction context (account, nonce) from request args.
285
+ */
286
+ async function extractTransactionContext(args) {
287
+ const account = args.account ?? walletClient.account;
288
+ const from = resolveAccountAddress(account);
289
+ if (!from) {
290
+ throw new Error('[TrackedWalletClient] No account available. ' +
291
+ 'Provide an account in the request or configure the wallet client with an account.');
292
+ }
293
+ const intendedNonce = await resolveNonce(args.nonce, from);
294
+ return { from, intendedNonce };
295
+ }
296
+ /**
297
+ * Extract transaction context from a serialized (signed) transaction.
298
+ */
299
+ async function extractRawTransactionContext(serializedTransaction) {
300
+ const parsedTx = parseTransaction(serializedTransaction);
301
+ if (parsedTx.nonce === undefined) {
302
+ throw new Error('[TrackedWalletClient] Could not extract nonce from serialized transaction.');
303
+ }
304
+ const from = await recoverTransactionAddress({
305
+ serializedTransaction,
306
+ });
307
+ return {
308
+ from,
309
+ intendedNonce: parsedTx.nonce,
310
+ };
311
+ }
312
+ /**
313
+ * Fetch the transaction after broadcast to verify nonce.
314
+ */
315
+ async function verifyTransactionNonce(hash, intendedNonce) {
316
+ try {
317
+ const tx = await publicClient.getTransaction({ hash });
318
+ const actualNonce = tx.nonce;
319
+ if (actualNonce !== intendedNonce) {
320
+ console.warn(`[TrackedWalletClient] Nonce mismatch: intended ${intendedNonce}, actual ${actualNonce}. ` +
321
+ `Wallet may have overridden the nonce.`);
322
+ }
323
+ return actualNonce;
324
+ }
325
+ catch (fetchError) {
326
+ console.warn(`[TrackedWalletClient] Could not fetch tx ${hash} after broadcast. ` +
327
+ `It may not be in the mempool yet.`);
328
+ return intendedNonce;
329
+ }
330
+ }
331
+ /**
332
+ * Create a tracked transaction record.
333
+ */
334
+ function createTrackedTransactionRecord(txHash, from, nonce, metadata) {
335
+ return {
336
+ hash: txHash,
337
+ from,
338
+ nonce,
339
+ chainId: walletClient.chain?.id,
340
+ metadata,
341
+ broadcastTimestampMs: Date.now(),
342
+ };
343
+ }
344
+ /**
345
+ * Validate that user didn't provide operation, functionName or args in metadata
346
+ * when populateMetadata is enabled.
347
+ */
348
+ function validateNoAutoPopulatedFieldsInMetadata(userMetadata) {
349
+ if (userMetadata && typeof userMetadata === 'object') {
350
+ if ('type' in userMetadata) {
351
+ throw new Error('[TrackedWalletClient] Cannot specify type in metadata when populateMetadata is enabled. ' +
352
+ 'The type is automatically populated from the contract call.');
353
+ }
354
+ if ('functionName' in userMetadata) {
355
+ throw new Error('[TrackedWalletClient] Cannot specify functionName in metadata when populateMetadata is enabled. ' +
356
+ 'The functionName is automatically populated from the contract call.');
357
+ }
358
+ if ('args' in userMetadata) {
359
+ throw new Error('[TrackedWalletClient] Cannot specify args in metadata when populateMetadata is enabled. ' +
360
+ 'The args are automatically populated from the contract call.');
361
+ }
362
+ }
363
+ }
364
+ /**
365
+ * Common wrapper for transaction methods that broadcast.
366
+ */
367
+ async function executeTrackedTransaction(args) {
368
+ const { metadata, restArgs, execute, extractHash } = args;
369
+ const { from, intendedNonce } = await extractTransactionContext(args);
370
+ const result = await execute({
371
+ ...restArgs,
372
+ nonce: intendedNonce,
373
+ });
374
+ const hash = extractHash(result);
375
+ const actualNonce = await verifyTransactionNonce(hash, intendedNonce);
376
+ const trackedTx = createTrackedTransactionRecord(hash, from, actualNonce, metadata);
377
+ emitter.emit('transaction:broadcasted', trackedTx);
378
+ return result;
379
+ }
380
+ /**
381
+ * Common wrapper for raw transaction broadcasts.
382
+ */
383
+ async function executeTrackedRawTransaction(args) {
384
+ const { serializedTransaction, metadata, execute, extractHash } = args;
385
+ const { from, intendedNonce } = await extractRawTransactionContext(serializedTransaction);
386
+ const result = await execute();
387
+ const hash = extractHash(result);
388
+ const trackedTx = createTrackedTransactionRecord(hash, from, intendedNonce, metadata);
389
+ emitter.emit('transaction:broadcasted', trackedTx);
390
+ return result;
391
+ }
392
+ return {
393
+ walletClient: walletClient,
394
+ publicClient,
395
+ // ============================================
396
+ // Async methods (return hash)
397
+ // ============================================
398
+ async writeContract(args) {
399
+ const { metadata: userMetadata, nonce, ...writeArgs } = args;
400
+ // Validate that user didn't provide operation, functionName or args
401
+ validateNoAutoPopulatedFieldsInMetadata(userMetadata);
402
+ // Auto-populate type, functionName and args
403
+ const finalMetadata = {
404
+ ...(userMetadata ?? {}),
405
+ type: 'functionCall',
406
+ functionName: args.functionName,
407
+ args: args.args,
408
+ };
409
+ return executeTrackedTransaction({
410
+ account: normalizeAccount(args.account),
411
+ nonce,
412
+ metadata: finalMetadata,
413
+ restArgs: writeArgs,
414
+ execute: (argsWithNonce) => walletClient.writeContract(argsWithNonce),
415
+ extractHash: (hash) => hash,
416
+ });
417
+ },
418
+ async sendTransaction(args) {
419
+ const { metadata, nonce, ...sendArgs } = args;
420
+ return executeTrackedTransaction({
421
+ account: normalizeAccount(args.account),
422
+ nonce,
423
+ metadata: metadata,
424
+ restArgs: sendArgs,
425
+ execute: (argsWithNonce) => walletClient.sendTransaction(argsWithNonce),
426
+ extractHash: (hash) => hash,
427
+ });
428
+ },
429
+ async sendRawTransaction(args) {
430
+ const { metadata, serializedTransaction } = args;
431
+ return executeTrackedRawTransaction({
432
+ serializedTransaction,
433
+ metadata: metadata,
434
+ execute: () => walletClient.sendRawTransaction({ serializedTransaction }),
435
+ extractHash: (hash) => hash,
436
+ });
437
+ },
438
+ // ============================================
439
+ // Sync methods (return receipt, wait for confirmation)
440
+ // ============================================
441
+ async writeContractSync(args) {
442
+ const { metadata: userMetadata, nonce, ...writeArgs } = args;
443
+ // Validate that user didn't provide operation, functionName or args
444
+ validateNoAutoPopulatedFieldsInMetadata(userMetadata);
445
+ // Auto-populate type, functionName and args
446
+ const finalMetadata = {
447
+ ...(userMetadata ?? {}),
448
+ type: 'functionCall',
449
+ functionName: args.functionName,
450
+ args: args.args,
451
+ };
452
+ return executeTrackedTransaction({
453
+ account: normalizeAccount(args.account),
454
+ nonce,
455
+ metadata: finalMetadata,
456
+ restArgs: writeArgs,
457
+ execute: (argsWithNonce) => walletClient.writeContractSync(argsWithNonce),
458
+ extractHash: (receipt) => receipt.transactionHash,
459
+ });
460
+ },
461
+ async sendTransactionSync(args) {
462
+ const { metadata, nonce, ...sendArgs } = args;
463
+ return executeTrackedTransaction({
464
+ account: normalizeAccount(args.account),
465
+ nonce,
466
+ metadata: metadata,
467
+ restArgs: sendArgs,
468
+ execute: (argsWithNonce) => walletClient.sendTransactionSync(argsWithNonce),
469
+ extractHash: (receipt) => receipt.transactionHash,
470
+ });
471
+ },
472
+ async sendRawTransactionSync(args) {
473
+ const { metadata, serializedTransaction } = args;
474
+ return executeTrackedRawTransaction({
475
+ serializedTransaction,
476
+ metadata: metadata,
477
+ execute: () => walletClient.sendRawTransactionSync({ serializedTransaction }),
478
+ extractHash: (receipt) => receipt.transactionHash,
479
+ });
480
+ },
481
+ // ============================================
482
+ // Event subscription methods
483
+ // ============================================
484
+ onTransactionBroadcasted: (listener) => emitter.on('transaction:broadcasted', listener),
485
+ offTransactionBroadcasted: (listener) => emitter.off('transaction:broadcasted', listener),
486
+ };
254
487
  },
255
- // ============================================
256
- // Event subscription methods
257
- // ============================================
258
- onTransactionBroadcasted: (listener) => emitter.on('transaction:broadcasted', listener),
259
- offTransactionBroadcasted: (listener) => emitter.off('transaction:broadcasted', listener),
260
488
  };
261
489
  }
262
490
  //# sourceMappingURL=TrackedWalletClient.js.map